nedb-engine 3.3.1 → 4.0.0
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/LICENSE +151 -21
- package/README.md +241 -20
- package/index.js +4 -0
- package/nedb-inspector.mjs +4 -0
- package/nedb.darwin-arm64.node +0 -0
- package/nedb.darwin-x64.node +0 -0
- package/nedb.linux-arm64-gnu.node +0 -0
- package/nedb.linux-arm64-musl.node +0 -0
- package/nedb.linux-x64-gnu.node +0 -0
- package/nedb.linux-x64-musl.node +0 -0
- package/nedb.win32-x64-msvc.node +0 -0
- package/nedbd-v2-darwin-arm64 +0 -0
- package/nedbd-v2-darwin-x64 +0 -0
- package/nedbd-v2-linux-arm64 +0 -0
- package/nedbd-v2-linux-arm64-musl +0 -0
- package/nedbd-v2-linux-x64 +0 -0
- package/nedbd-v2-linux-x64-musl +0 -0
- package/nedbd-v2-win-x64.exe +0 -0
- package/nedbd-v2.js +4 -0
- package/package.json +2 -2
- package/test/durability.test.mjs +4 -0
- package/test/smoke.mjs +4 -0
- package/wrap/index.js +4 -0
- package/wrap/mongo.js +4 -0
- package/wrap/redis.js +4 -0
- package/wrap/sql.js +4 -0
- package/wrap/surface.js +4 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,151 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
|
|
4
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
5
|
+
|
|
6
|
+
-----------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
|
|
10
|
+
Licensor: INTERCHAINED LLC
|
|
11
|
+
|
|
12
|
+
Licensed Work: NEDB, version 4.0.0 and later.
|
|
13
|
+
The Licensed Work is (c) 2026 INTERCHAINED LLC.
|
|
14
|
+
|
|
15
|
+
Additional Use Grant: You may make production use of the Licensed Work,
|
|
16
|
+
without limitation and without obtaining any further
|
|
17
|
+
permission or license from the Licensor, provided that
|
|
18
|
+
your Annual Revenue is less than one million United
|
|
19
|
+
States dollars (USD $1,000,000).
|
|
20
|
+
|
|
21
|
+
"Annual Revenue" means the total gross revenue,
|
|
22
|
+
recognised under the accounting standards you ordinarily
|
|
23
|
+
apply, of you together with all of your Affiliates, over
|
|
24
|
+
your most recently completed fiscal year. "Affiliates"
|
|
25
|
+
means any entity that controls, is controlled by, or is
|
|
26
|
+
under common control with you, where "control" means
|
|
27
|
+
direct or indirect ownership of more than fifty percent
|
|
28
|
+
(50%) of the voting interests of an entity.
|
|
29
|
+
|
|
30
|
+
Annual Revenue is measured on your organisation as a
|
|
31
|
+
whole. It is NOT limited to revenue derived from, or
|
|
32
|
+
attributable to, the Licensed Work. An organisation
|
|
33
|
+
whose Annual Revenue is USD $1,000,000 or more must
|
|
34
|
+
obtain an additional use grant from the Licensor before
|
|
35
|
+
making production use of the Licensed Work.
|
|
36
|
+
|
|
37
|
+
Regardless of Annual Revenue, this Additional Use Grant
|
|
38
|
+
does not permit you to offer the Licensed Work, or a
|
|
39
|
+
substantially similar derivative of it, to third parties
|
|
40
|
+
as a managed, hosted or database-as-a-service offering.
|
|
41
|
+
That use requires a separate commercial license.
|
|
42
|
+
|
|
43
|
+
Non-production use is always permitted: development,
|
|
44
|
+
testing, continuous integration, evaluation, research,
|
|
45
|
+
teaching and personal projects are unrestricted for
|
|
46
|
+
everyone, at any revenue.
|
|
47
|
+
|
|
48
|
+
To obtain an additional use grant, contact
|
|
49
|
+
licensing@interchained.org.
|
|
50
|
+
|
|
51
|
+
Change Date: 2030-09-11
|
|
52
|
+
|
|
53
|
+
Change License: Apache License, Version 2.0
|
|
54
|
+
The full text ships in this repository as
|
|
55
|
+
COPYING-APACHE-2.0.txt, so the grant is verifiable from
|
|
56
|
+
the source tree alone.
|
|
57
|
+
|
|
58
|
+
The Change License relicenses the Licensed Work's OWN
|
|
59
|
+
source. It does not relicense third-party dependencies,
|
|
60
|
+
which keep their own terms — inventoried in
|
|
61
|
+
THIRD_PARTY.md.
|
|
62
|
+
|
|
63
|
+
-----------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
Terms
|
|
66
|
+
|
|
67
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
68
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
69
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
70
|
+
production use.
|
|
71
|
+
|
|
72
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
73
|
+
available distribution of a specific version of the Licensed Work under this
|
|
74
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
75
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
76
|
+
above terminate.
|
|
77
|
+
|
|
78
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
79
|
+
currently in effect as described in this License, you must purchase a
|
|
80
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
81
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
82
|
+
|
|
83
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
84
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
85
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
86
|
+
for each version of the Licensed Work released by Licensor.
|
|
87
|
+
|
|
88
|
+
You must conspicuously display this License on each original or modified copy
|
|
89
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
90
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
91
|
+
License apply to your use of that work.
|
|
92
|
+
|
|
93
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
94
|
+
terminate your rights under this License for the current and all other
|
|
95
|
+
versions of the Licensed Work.
|
|
96
|
+
|
|
97
|
+
This License does not grant you any right in any trademark or logo of
|
|
98
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
99
|
+
Licensor as expressly required by this License).
|
|
100
|
+
|
|
101
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
102
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
103
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
104
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
105
|
+
TITLE.
|
|
106
|
+
|
|
107
|
+
MariaDB hereby grants you permission to use this License's text to license
|
|
108
|
+
your works, and to refer to it using the trademark "Business Source License",
|
|
109
|
+
as long as you comply with the Covenants of Licensor below.
|
|
110
|
+
|
|
111
|
+
-----------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
Covenants of Licensor
|
|
114
|
+
|
|
115
|
+
In consideration of the right to use this License's text and the "Business
|
|
116
|
+
Source License" name and trademark, Licensor covenants to MariaDB, and to all
|
|
117
|
+
other recipients of the licensed work to be provided by Licensor:
|
|
118
|
+
|
|
119
|
+
1. To specify as the Change License the GPL Version 2.0 or any later version,
|
|
120
|
+
or a license that is compatible with GPL Version 2.0 or a later version,
|
|
121
|
+
where "compatible" means that software provided under the Change License
|
|
122
|
+
can be included in a program with software provided under GPL Version 2.0
|
|
123
|
+
or a later version. Licensor may specify additional Change Licenses
|
|
124
|
+
without limitation.
|
|
125
|
+
|
|
126
|
+
2. To either: (a) specify an additional grant of rights to use that does not
|
|
127
|
+
impose any additional restriction on the right granted in this License, as
|
|
128
|
+
the Additional Use Grant; or (b) insert the text "None".
|
|
129
|
+
|
|
130
|
+
3. To specify a Change Date.
|
|
131
|
+
|
|
132
|
+
4. Not to modify this License in any other way.
|
|
133
|
+
|
|
134
|
+
-----------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
Notice
|
|
137
|
+
|
|
138
|
+
The Business Source License (this document, or the "License") is not an Open
|
|
139
|
+
Source license. However, the Licensed Work will eventually be made available
|
|
140
|
+
under an Open Source License, as stated in this License.
|
|
141
|
+
|
|
142
|
+
-----------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
Prior versions
|
|
145
|
+
|
|
146
|
+
NEDB versions 3.0.0 through 3.3.1 were released under the MIT License. That
|
|
147
|
+
grant is irrevocable for those versions: if you obtained NEDB at 3.3.1 or
|
|
148
|
+
earlier, your rights in that copy are unchanged by this License and are not
|
|
149
|
+
affected by it. This License governs version 4.0.0 and later only.
|
|
150
|
+
|
|
151
|
+
© 2026 INTERCHAINED LLC
|
package/README.md
CHANGED
|
@@ -13,14 +13,19 @@ One Rust core → ships to **PyPI** and **npm** from a single source.
|
|
|
13
13
|
[](https://github.com/Eth-Interchained/nedb/actions)
|
|
14
14
|
[](https://pypi.org/project/nedb-engine-client/)
|
|
15
15
|
[](https://www.npmjs.com/package/nedb-engine-client)
|
|
16
|
-
[](https://github.com/Eth-Interchained/nedb/blob/master/LICENSE) [](https://github.com/Eth-Interchained/nedb/blob/master/LICENSE)
|
|
17
17
|
|
|
18
18
|
**[Studio → studio.interchained.org](https://studio.interchained.org)** · **[nedb.aiassist.net](https://nedb.aiassist.net)**
|
|
19
19
|
|
|
20
|
-
> ## 🟢
|
|
21
|
-
> NEDB is licensed under the **
|
|
22
|
-
>
|
|
23
|
-
>
|
|
20
|
+
> ## 🟢 Free in production under $1M revenue
|
|
21
|
+
> NEDB 4.0.0 is licensed under the **Business Source License 1.1**. If your organisation's annual
|
|
22
|
+
> revenue is **under USD $1,000,000**, you may use it in production — commercially, embedded, in
|
|
23
|
+
> closed-source software — with **no permission needed and no royalty**. At **$1M or more**, you
|
|
24
|
+
> need an additional use grant from Interchained LLC: **licensing@interchained.org**.
|
|
25
|
+
>
|
|
26
|
+
> Non-production use is unrestricted for everyone, at any revenue: development, testing, CI,
|
|
27
|
+
> evaluation, research, teaching. On **2030-09-11** this version converts to **Apache 2.0**
|
|
28
|
+
> automatically and permanently. See [`LICENSE`](LICENSE).
|
|
24
29
|
|
|
25
30
|
</div>
|
|
26
31
|
|
|
@@ -98,45 +103,261 @@ identical answers.
|
|
|
98
103
|
|
|
99
104
|
---
|
|
100
105
|
|
|
106
|
+
## Postgres wire protocol — run your SQL, get history for free
|
|
107
|
+
|
|
108
|
+
`nedbd --pg-port 5433` opens a **PostgreSQL wire-protocol endpoint** — reads
|
|
109
|
+
*and* writes. `psql`, DBeaver, Metabase, Grafana, psycopg — anything that
|
|
110
|
+
speaks pgwire can use a tamper-evident NEDB store with ordinary SQL, with no
|
|
111
|
+
bespoke client.
|
|
112
|
+
|
|
113
|
+
**The reason the write path matters** is that SQL's write semantics and NEDB's
|
|
114
|
+
append-only model already line up:
|
|
115
|
+
|
|
116
|
+
| SQL | NEDB | and therefore |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| `INSERT` | a put | — |
|
|
119
|
+
| `UPDATE … WHERE` | a **new version** of each match | the prior value stays readable |
|
|
120
|
+
| `DELETE … WHERE` | a **tombstone** | the deleted row stays in history |
|
|
121
|
+
|
|
122
|
+
So this is not a compromise of the append-only design — it *is* the design,
|
|
123
|
+
reached through a protocol every tool already speaks:
|
|
124
|
+
|
|
125
|
+
```sql
|
|
126
|
+
UPDATE orders SET total = 999 WHERE _id = 'o1';
|
|
127
|
+
SELECT total FROM orders WHERE _id = 'o1'; -- 999
|
|
128
|
+
SELECT total FROM orders AS OF SYSTEM TIME 0 WHERE _id = 'o1'; -- 120
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Run the SQL you would run against Postgres, and the tamper-evident audit trail
|
|
132
|
+
is free. No triggers, no shadow table, no application code. `verify()` still
|
|
133
|
+
passes afterwards, because a SQL write is an ordinary engine write and not a
|
|
134
|
+
side door around the hash chain.
|
|
135
|
+
|
|
136
|
+
Writes are **on by default**. `NEDBD_PG_READ_ONLY=1` gives the deployment where
|
|
137
|
+
this door must never mutate anything.
|
|
138
|
+
|
|
139
|
+
```console
|
|
140
|
+
$ nedbd --data ./data --pg-port 5433
|
|
141
|
+
pgwire postgres endpoint on 127.0.0.1:5433 — psql / DBeaver / psycopg (SELECT + INSERT/UPDATE/DELETE)
|
|
142
|
+
|
|
143
|
+
$ psql -h 127.0.0.1 -p 5433 -d shop
|
|
144
|
+
shop=> SELECT status, total FROM orders WHERE status IN ('paid','open') ORDER BY total DESC;
|
|
145
|
+
status | total
|
|
146
|
+
--------+-------
|
|
147
|
+
paid | 300
|
|
148
|
+
paid | 120
|
|
149
|
+
open | 40
|
|
150
|
+
|
|
151
|
+
shop=> SELECT SUM(total) FROM orders WHERE region = 'eu';
|
|
152
|
+
sum
|
|
153
|
+
-----
|
|
154
|
+
420
|
|
155
|
+
|
|
156
|
+
shop=> SELECT * FROM orders AS OF SYSTEM TIME 1; -- time travel, in SQL
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**`AS OF SYSTEM TIME` is the bridge worth knowing about.** It is the spelling
|
|
160
|
+
Postgres and CockroachDB use, and here it reaches NEDB's permanent,
|
|
161
|
+
never-garbage-collected history rather than a few hours of MVCC.[^compact] A wall-clock
|
|
162
|
+
timestamp is refused with the reason: NEDB's history is sequence-addressed, so
|
|
163
|
+
a seq is exact where a time would be approximate.
|
|
164
|
+
|
|
165
|
+
[^compact]: One caveat, stated rather than buried. `Db::compact()` reclaims disk
|
|
166
|
+
space by rewriting the object segments with only each document's **current**
|
|
167
|
+
version — so it prunes superseded versions and tombstones, and `AS OF` can
|
|
168
|
+
no longer reach them. Nothing invokes it automatically: it is not on the
|
|
169
|
+
HTTP surface, not in the CLI, and not on any timer. It exists for the
|
|
170
|
+
operator who has explicitly chosen to trade the audit trail for space. A
|
|
171
|
+
compacted store answers "not available at that sequence" rather than
|
|
172
|
+
returning a stale value, and `verify()` stays clean.
|
|
173
|
+
|
|
174
|
+
Provenance is selectable like any other column:
|
|
175
|
+
|
|
176
|
+
```sql
|
|
177
|
+
SELECT _id, _hash, _seq FROM audit ORDER BY _seq;
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**This is not "NEDB speaks SQL", and the endpoint is careful to say so.** It is
|
|
181
|
+
a documented subset of `SELECT` translated to NQL:
|
|
182
|
+
|
|
183
|
+
| Supported | Refused, with the reason |
|
|
184
|
+
| --- | --- |
|
|
185
|
+
| `*`, a column list, `COUNT(*)`, `SUM`/`AVG`/`MIN`/`MAX(col)` | `JOIN` — NQL is single-collection |
|
|
186
|
+
| `WHERE` — the whole NQL predicate surface | subqueries, `UNION`, window functions |
|
|
187
|
+
| `GROUP BY`, `HAVING`, `ORDER BY`, `LIMIT`, `OFFSET` | expressions in the select list |
|
|
188
|
+
| `AS OF SYSTEM TIME <seq>` | DDL, `TRUNCATE`, `GRANT`/`REVOKE` |
|
|
189
|
+
| `INSERT` / `UPDATE` / `DELETE`, all with `RETURNING` | an `INSERT` with no column list |
|
|
190
|
+
| `_caused_by` / `_valid_from` / `_valid_to` as INSERT columns | values that are expressions, not literals |
|
|
191
|
+
|
|
192
|
+
Every refusal names the boundary instead of saying "syntax error", and a
|
|
193
|
+
grouped query that projects a column SQL would reject gets Postgres's own
|
|
194
|
+
message rather than a silent `NULL`.
|
|
195
|
+
|
|
196
|
+
**Provenance is settable from SQL**, so the causal chain does not require the
|
|
197
|
+
HTTP API:
|
|
198
|
+
|
|
199
|
+
```sql
|
|
200
|
+
INSERT INTO audit (_id, _caused_by, kind) VALUES ('leaf', '<parent-hash>', 'reprice');
|
|
201
|
+
SELECT _id FROM audit TRACE caused_by;
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
An `INSERT` requires an explicit column list, because NEDB is schemaless and
|
|
205
|
+
there is no declared column order to infer. Values must be literals — a number,
|
|
206
|
+
a quoted string, `TRUE`/`FALSE`/`NULL` — since storing an unevaluated
|
|
207
|
+
expression as text would be worse than refusing it.
|
|
208
|
+
|
|
209
|
+
### Your driver, not just `psql`
|
|
210
|
+
|
|
211
|
+
**Both wire protocols are implemented**, which is the difference between "psql
|
|
212
|
+
works" and "your application framework works":
|
|
213
|
+
|
|
214
|
+
| Protocol | Used by | Status |
|
|
215
|
+
| --- | --- | --- |
|
|
216
|
+
| simple (`Q`) | `psql`, libpq/`PQexec`, **psycopg2** | ✅ |
|
|
217
|
+
| extended (`Parse`/`Bind`/`Describe`/`Execute`) | **psycopg3**, **asyncpg**, **JDBC** | ✅ |
|
|
218
|
+
|
|
219
|
+
Those last three send `Parse`/`Bind` for every parameterised statement, so
|
|
220
|
+
until the extended protocol landed they could not run a *single* query — not
|
|
221
|
+
slower, not degraded: psycopg3 hung and asyncpg refused outright.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
# psycopg3 — parameters are bound server-side
|
|
225
|
+
cur.execute("SELECT _id, total FROM orders WHERE status = %s AND total > %s",
|
|
226
|
+
("paid", 100))
|
|
227
|
+
|
|
228
|
+
# asyncpg — same statement, same endpoint
|
|
229
|
+
await conn.fetch("SELECT _id, total FROM orders WHERE status = $1 AND total > $2",
|
|
230
|
+
"paid", 100)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Parameters arrive in text **and binary** format (psycopg3 sends a small `int`
|
|
234
|
+
as binary int2, a float as binary float8), and a row-capped `Execute` suspends
|
|
235
|
+
its portal, so a JDBC `setFetchSize` pages a large result instead of stalling.
|
|
236
|
+
|
|
237
|
+
**Typing parameters in a store with no schema** is the interesting part. A
|
|
238
|
+
relational server reads `$1`'s type out of its catalogue; NEDB has no
|
|
239
|
+
catalogue, so the type is sampled from the documents already stored — the
|
|
240
|
+
stored data *is* the schema. Where a placeholder sits in a clause rather than
|
|
241
|
+
beside a column (`AS OF SYSTEM TIME $1`, `LIMIT $1`) the grammar supplies the
|
|
242
|
+
type, and an aggregate is typed from what it means: a `COUNT` is an integer, an
|
|
243
|
+
`AVG` fractional, a `MAX` whatever the field it ranges over is.
|
|
244
|
+
|
|
245
|
+
A driver that declares its own parameter types is believed, and only its
|
|
246
|
+
unspecified slots are inferred.
|
|
247
|
+
|
|
248
|
+
### Limits, stated plainly
|
|
249
|
+
|
|
250
|
+
SQL-level cursors (`DECLARE`/`FETCH`) and `pg_catalog` introspection are not
|
|
251
|
+
implemented, so `\dt` and DBeaver's schema browser come back empty — both are
|
|
252
|
+
refused by name rather than hanging. A column whose stored values disagree
|
|
253
|
+
about their type across documents is advertised as `text`, and cannot be sent
|
|
254
|
+
in binary format.
|
|
255
|
+
|
|
256
|
+
And the connection is **cleartext**, which is why the endpoint is off unless
|
|
257
|
+
you pass `--pg-port` and binds to loopback by default. Put it behind a tunnel
|
|
258
|
+
to go further.
|
|
259
|
+
|
|
260
|
+
Verified in CI by `tests/test_pgwire.py` — **64 checks driven through psycopg2,
|
|
261
|
+
which is libpq**. Unit tests can prove the translation; only a real client
|
|
262
|
+
proves the protocol. One of those checks is the one that matters: after a plain
|
|
263
|
+
SQL `UPDATE`, the prior value is still readable at its original sequence.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
101
267
|
## New in 3.2.0 — wrap the databases you already run
|
|
102
268
|
|
|
103
269
|
NEDB adds **tamper-evident causal provenance to a database you already have**, in one line, without
|
|
104
270
|
rip-and-replace. Five adapters, one surface:
|
|
105
271
|
|
|
272
|
+
**One flag. No table list, no registration, no per-write calls.**
|
|
273
|
+
|
|
106
274
|
```python
|
|
107
|
-
from nedb import
|
|
275
|
+
from nedb import wrap_postgresql
|
|
276
|
+
import psycopg2
|
|
277
|
+
|
|
278
|
+
conn = wrap_postgresql(psycopg2.connect("dbname=app"), db_name="app")
|
|
279
|
+
conn.nedb.shadow_writes = True # ← that is the whole setup
|
|
280
|
+
|
|
281
|
+
# Your app runs UNCHANGED.
|
|
282
|
+
cur = conn.cursor()
|
|
283
|
+
cur.execute("INSERT INTO drivers (name, status) VALUES (%s, %s)", ("Bob", "active"))
|
|
284
|
+
cur.execute("UPDATE drivers SET status = %s WHERE name = %s", ("off", "Bob"))
|
|
285
|
+
conn.commit()
|
|
108
286
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
287
|
+
conn.nedb.query('FROM drivers WHERE status = "off"') # NQL over your Postgres data
|
|
288
|
+
conn.nedb.query('FROM drivers AS OF 0') # → status "active", the prior value
|
|
289
|
+
conn.nedb.verify() # True — BLAKE2b chain intact
|
|
290
|
+
```
|
|
113
291
|
|
|
114
|
-
|
|
292
|
+
Setting the flag reads the host's own catalogue and mirrors **every table**, with its
|
|
293
|
+
real primary key. Coverage is **opt-out**, because opt-in auditing has a worse failure
|
|
294
|
+
mode than none: three tables registered out of twelve looks exactly like a complete
|
|
295
|
+
audit trail until the day you need it.
|
|
115
296
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
297
|
+
```python
|
|
298
|
+
conn.nedb.exclude = {"sessions", "audit_log_*"} # tables to leave alone
|
|
299
|
+
conn.nedb.exclude_columns = {"password_hash", "ssn"} # columns that must NEVER be mirrored
|
|
300
|
+
assert not conn.nedb.unmirrored_tables # a real check, not a hope
|
|
119
301
|
```
|
|
120
302
|
|
|
303
|
+
`exclude_columns` is the one setting that is about correctness rather than convenience.
|
|
304
|
+
**NEDB cannot forget** — that is the product, and it is exactly wrong for a secret or for
|
|
305
|
+
a row somebody has a right to erase. Nothing is excluded by default; guessing which of
|
|
306
|
+
your columns are sensitive would be its own silent wrong answer.
|
|
307
|
+
|
|
121
308
|
| wrapper | host | shadowing |
|
|
122
309
|
|---|---|---|
|
|
123
|
-
| `wrap_redis` | `redis.Redis` / compatible | automatic — every write command intercepted |
|
|
124
|
-
| `wrap_sqlite` | `sqlite3.Connection` | automatic — `execute
|
|
310
|
+
| `wrap_redis` | `redis.Redis` / compatible | **automatic** — every write command intercepted |
|
|
311
|
+
| `wrap_sqlite` | `sqlite3.Connection` | **automatic** — `conn.execute`, `cursor.execute`, `executemany` |
|
|
312
|
+
| `wrap_postgresql` | DB-API 2.0 (psycopg2, psycopg 3) | **automatic** — every cursor write, via `RETURNING` |
|
|
125
313
|
| `wrap_mysql` | DB-API 2.0 (mysql-connector, PyMySQL) | explicit `shadow_row()` |
|
|
126
314
|
| `wrap_mongo` | `pymongo.MongoClient` | explicit `shadow_row()` |
|
|
127
|
-
| `wrap_postgresql` | DB-API 2.0 (psycopg2, psycopg 3) | explicit `shadow_row()` |
|
|
128
315
|
|
|
129
316
|
**NEDB never writes into the host database's namespace.** Shadow data lives only in the NEDB engine.
|
|
130
317
|
|
|
318
|
+
### The limit, stated plainly
|
|
319
|
+
|
|
320
|
+
Interception sees writes made **through this connection**. Your production Postgres is
|
|
321
|
+
also written by `psql`, cron jobs, migration tools, and other services — and none of
|
|
322
|
+
those pass through here. For whole-database coverage independent of the client, the right
|
|
323
|
+
mechanism is Postgres **logical replication** (a replication slot decoded with the
|
|
324
|
+
built-in `pgoutput`), which observes every committed change whatever made it. That needs
|
|
325
|
+
`wal_level = logical` and a replication role, and it is not implemented yet.
|
|
326
|
+
|
|
327
|
+
So this covers your application's writes completely, and it does not pretend to cover
|
|
328
|
+
writes it cannot see. A write to a table that could not be mirrored lands in
|
|
329
|
+
`nedb.unmirrored_tables` rather than vanishing.
|
|
330
|
+
|
|
131
331
|
Three backends behind the same surface, selected by `backend="auto"`: **nedbd over HTTP** (`nedbd_url=`),
|
|
132
332
|
**embedded v2/v3 DAG** (the Rust core, in-process, no server — `dag_path=` for a durable store,
|
|
133
333
|
`dag_tmk=` for AES-256-GCM at rest), or the **v1 in-process AOF** engine as a universal fallback. On the
|
|
134
334
|
DAG backend you also get `tip()`, `tip_collection()`, `since()` (changefeed) and `scan_status()`.
|
|
135
335
|
|
|
136
|
-
###
|
|
336
|
+
### Licensing — BUSL-1.1 as of 4.0.0
|
|
137
337
|
|
|
138
|
-
|
|
139
|
-
|
|
338
|
+
| Your annual revenue | Production use |
|
|
339
|
+
|---|---|
|
|
340
|
+
| **under USD $1,000,000** | **free.** No permission, no royalty, no registration. Commercial, embedded and closed-source all included. |
|
|
341
|
+
| **USD $1,000,000 or more** | needs an additional use grant — **licensing@interchained.org** |
|
|
342
|
+
|
|
343
|
+
Measured on your whole organisation, not on revenue attributable to NEDB. Non-production use —
|
|
344
|
+
development, testing, CI, evaluation, research, teaching — is unrestricted for **everyone**, at any
|
|
345
|
+
revenue. Offering NEDB itself as a hosted database service needs a separate commercial license
|
|
346
|
+
regardless of revenue.
|
|
347
|
+
|
|
348
|
+
**Change Date 2030-09-11**: this version becomes **Apache 2.0** on that date, automatically. The
|
|
349
|
+
grant is in the license text, not a promise — nobody has to be asked, and it cannot be withdrawn.
|
|
350
|
+
The full Apache text ships as [`COPYING-APACHE-2.0.txt`](COPYING-APACHE-2.0.txt) so that is
|
|
351
|
+
verifiable from the source tree alone.
|
|
352
|
+
|
|
353
|
+
Every source file carries `SPDX-License-Identifier: BUSL-1.1`, so license scanners read the terms
|
|
354
|
+
out of the code rather than guessing. Dependencies keep their own licenses — the Change License
|
|
355
|
+
never relicenses them — and they are inventoried in [`THIRD_PARTY.md`](THIRD_PARTY.md). There is
|
|
356
|
+
**no GPL, AGPL, SSPL or BUSL third-party dependency** in the tree; all 206 third-party crates are
|
|
357
|
+
permissive, and the two Python runtime dependencies are BSD and Apache.
|
|
358
|
+
|
|
359
|
+
**Versions 3.0.0 – 3.3.1 stay MIT, irrevocably.** If you already have NEDB at 3.3.1 or earlier, your
|
|
360
|
+
rights in that copy are untouched. This applies to 4.0.0 and later only.
|
|
140
361
|
|
|
141
362
|
### Also in 3.2.0
|
|
142
363
|
|
package/index.js
CHANGED
package/nedb-inspector.mjs
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 INTERCHAINED LLC
|
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
4
|
+
// NEDB · © 2026 INTERCHAINED LLC × Eth-Interchained × Vex (Claude Opus 5)
|
|
5
|
+
|
|
2
6
|
// nedb-inspector — deterministic embedder-code checker for NEDB durability.
|
|
3
7
|
//
|
|
4
8
|
// nedb-inspector.mjs <pathToTarget.(rs|js|mjs|ts|py)> [more paths...]
|
package/nedb.darwin-arm64.node
CHANGED
|
Binary file
|
package/nedb.darwin-x64.node
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/nedb.linux-x64-gnu.node
CHANGED
|
Binary file
|
package/nedb.linux-x64-musl.node
CHANGED
|
Binary file
|
package/nedb.win32-x64-msvc.node
CHANGED
|
Binary file
|
package/nedbd-v2-darwin-arm64
CHANGED
|
Binary file
|
package/nedbd-v2-darwin-x64
CHANGED
|
Binary file
|
package/nedbd-v2-linux-arm64
CHANGED
|
Binary file
|
|
Binary file
|
package/nedbd-v2-linux-x64
CHANGED
|
Binary file
|
package/nedbd-v2-linux-x64-musl
CHANGED
|
Binary file
|
package/nedbd-v2-win-x64.exe
CHANGED
|
Binary file
|
package/nedbd-v2.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 INTERCHAINED LLC
|
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
4
|
+
// NEDB · © 2026 INTERCHAINED LLC × Eth-Interchained × Vex (Claude Opus 5)
|
|
5
|
+
|
|
2
6
|
// nedbd-v2 — thin platform shim that locates and spawns the right
|
|
3
7
|
// pre-built native binary for the current platform/arch.
|
|
4
8
|
//
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nedb-engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "NEDB \u2014 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
|
"exports": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"README.md",
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
|
-
"license": "
|
|
34
|
+
"license": "BUSL-1.1",
|
|
35
35
|
"homepage": "https://github.com/aiassistsecure/nedb#readme",
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|
package/test/durability.test.mjs
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 INTERCHAINED LLC
|
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
4
|
+
// NEDB · © 2026 INTERCHAINED LLC × Eth-Interchained × Vex (Claude Opus 5)
|
|
5
|
+
|
|
2
6
|
// nedb-engine — embedded durability under SIGKILL (2.8.5)
|
|
3
7
|
// ---------------------------------------------------------------------------
|
|
4
8
|
// The contract: an acknowledged write is on disk within one manifest tick (default 1 s) or at
|
package/test/smoke.mjs
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 INTERCHAINED LLC
|
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
4
|
+
// NEDB · © 2026 INTERCHAINED LLC × Eth-Interchained × Vex (Claude Opus 5)
|
|
5
|
+
|
|
2
6
|
// nedb-engine — cinematic smoke test (`npm test`)
|
|
3
7
|
// ---------------------------------------------------------------------------
|
|
4
8
|
// A five-act tour of the engine, driven entirely by the real native addon
|
package/wrap/index.js
CHANGED
package/wrap/mongo.js
CHANGED
package/wrap/redis.js
CHANGED
package/wrap/sql.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 INTERCHAINED LLC
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
// NEDB · © 2026 INTERCHAINED LLC × Eth-Interchained × Vex (Claude Opus 5)
|
|
4
|
+
|
|
1
5
|
'use strict';
|
|
2
6
|
// nedb/wrap/sql.js — wrapSqlite / wrapMysql / wrapPg: causal provenance for
|
|
3
7
|
// SQL databases (JS).
|
package/wrap/surface.js
CHANGED