anchordb-angular 1.3.3 → 1.4.1

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +479 -0
  2. package/README.md +6 -0
  3. package/package.json +4 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,479 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `anchordb` packages.
4
+
5
+ This project follows [semantic versioning](https://semver.org/). While the version is `0.x`, minor
6
+ releases may contain breaking changes.
7
+
8
+ ## 1.4.1
9
+
10
+ **Security: `anchordb-sync-server` now keeps users apart.** Up to 1.4.0 the server checked the
11
+ identity `authenticate` returned and then dropped it: every user pulled every user's documents and
12
+ could change or delete any of them by id. Every version before 1.4.1 is affected. Found by the
13
+ expense-tracker team.
14
+
15
+ ### Fixed
16
+
17
+ - **Each document belongs to a scope**, `user:<id>` for the user who created it, and a user reads and
18
+ changes only their own. `authenticate` may return a user id, as before, or
19
+ `{ userId, scopes }` to give a user further scopes (shared books, from 1.5.0).
20
+ - **Refusals reveal nothing.** Someone else's document is answered exactly as one that does not
21
+ exist: `rejected` with `code: 404`.
22
+ - **Retry answers and unique checks are per user.** Remembered answers are keyed by user as well as
23
+ `clientId`, so one user can't read back another's. Unique indexes are checked within the user's
24
+ documents; `{ global: true }` on a unique index checks across everyone (for usernames, say).
25
+ - **Fails closed.** Calling `handlePush`/`handlePull` yourself on a server with `authenticate` and no
26
+ caller is refused with 401. The Express, Next.js and NestJS adapters pass the caller for you.
27
+ - **A server with no `authenticate` warns at startup**, since every caller then shares every
28
+ document. Pass `singleUser: true` if that is what you want; it becomes required in 1.5.0.
29
+
30
+ ### New
31
+
32
+ - **`adoptUnscoped(options, { assignScope })`.** Documents written before 1.4.1 have no scope, and a
33
+ server with `authenticate` hides them from everyone until this one-time command assigns them, for
34
+ example `assignScope: (collection, doc) => doc.userId ? "user:" + doc.userId : null`. Each one it
35
+ assigns is sent to its owner's phones again. It is safe to run twice, and two processes running it
36
+ at once don't assign anything twice. A server that only one person used can assign everything to
37
+ that person: `() => "user:<their id>"`.
38
+ - **Epoch.** Every response carries an `epoch` (default `"2"` with `authenticate`; set `epoch` to
39
+ change it). When a phone sees a new one, it deletes its synced copy and pulls again, keeping its
40
+ unsent changes (`sync:reset` event). That clears out other users' documents that phones pulled from
41
+ 1.4.0 servers.
42
+ - **Protocol version 2.** A server with `authenticate` answers phones built with an older anchordb
43
+ `426 Update the app`, since they ignore the epoch. `legacyClients: "allow"` serves them for a
44
+ transition period. They are still kept apart, but they keep whatever they already pulled.
45
+ - **Pull limit** capped at 1000 changes (`maxPullLimit`).
46
+ - **Each pulled change carries its `scope`**, and the phone records it with the document.
47
+
48
+ ### Changed on the phone (`anchordb`)
49
+
50
+ - A change refused with 404 is parked, as before, and the phone now also deletes its copy of that
51
+ document — so another user's document that was edited offline doesn't stay on the phone. A
52
+ refused insert keeps the user's new document.
53
+ - **A document deleted on the user's other phone** now comes back as a conflict marked
54
+ `deleted: true` with `document: null`, and goes through the conflict strategy: `server-wins`
55
+ accepts the delete; `last-write-wins` keeps a newer local edit and brings the document back;
56
+ `client-wins` always brings it back; `field-level` falls back to last-write-wins. A custom
57
+ `resolver` receives `remote: null`, and returns null to accept the delete. The `conflict` event
58
+ gains `remoteDeleted` and `resolvedDeleted`.
59
+
60
+ ### Upgrading — in this order
61
+
62
+ 1. **Upgrade the server** to `anchordb-sync-server@1.4.1`.
63
+ 2. **Run `adoptUnscoped`** once with an `assignScope` that knows whose each document is. Until you
64
+ do, those documents are hidden from everyone. Nothing is ever deleted on the server.
65
+ 3. **Ship a new app build** with `anchordb@1.4.1`. On its first sync it starts over once, because of
66
+ the new epoch, and its unsent changes are kept.
67
+
68
+ App builds that use an anchordb version before 1.4.1 **stop syncing** (426) until users install the
69
+ update, unless the server sets `legacyClients: "allow"`. A server without `authenticate` is unchanged:
70
+ it still serves everyone everything, and still accepts old phones.
71
+
72
+ ## 1.4.0
73
+
74
+ **Transactions, migrations, recovery, TTL indexes, encryption, a test kit — and guides that ship in the
75
+ package.** Asked for by the expense-tracker team after building an offline-first app on 1.3; every
76
+ item has tests, and nothing existing changes behaviour except as noted.
77
+
78
+ ### New
79
+
80
+ - **`db.transaction(async (session) => …)`** — writes across collections, all or nothing, with
81
+ Mongoose's API: `{ session }` on `create`, `insertOne/Many`, `update*`, `replaceOne`, `delete*`,
82
+ `findOneAnd*`, `bulkWrite`, `aggregate`, the index methods and `doc.save()`, and `.session()` on
83
+ queries. A throw rolls every collection back; `change` events and queued sync mutations wait for
84
+ the commit. A call inside made without the session times out the transaction with
85
+ `TransactionTimeoutError` (`transactionTimeoutMs`, default 30 s) instead of hanging. Expo, Capacitor,
86
+ `node:sqlite` and memory; IndexedDB refuses with an explanation. `AnchorSession` / `ClientSession`.
87
+ - **Versioned migrations**: `createAnchorDB({ version, migrations: { 2: async (ctx) => … } })`, run by
88
+ `open()`, each step in its own transaction that records the version reached. A failed step is
89
+ rolled back and reported as `MigrationError`; `open()` can be retried. Older apps refuse newer data.
90
+ - **Recovery**: open failures are `DatabaseOpenError`, or `CorruptDatabaseError` /
91
+ `DatabaseLockedError`, with the driver's error as `cause`. `db.reset()` deletes the storage even
92
+ when it no longer opens. `integrityCheck: true` runs `PRAGMA quick_check` on open.
93
+ `db.rebuildIndexes()` rebuilds index entries from the documents.
94
+ - **TTL indexes are enforced.** `expireAfterSeconds` was stored and never applied; a sweep now deletes
95
+ expired documents with MongoDB's rules, every 60 s (`ttlIntervalMs`, `ttl: false`), and `db.expire()`
96
+ sweeps on demand.
97
+ - **Encryption**: `ExpoSqliteAdapter({ encryptionKey })` opens the file with SQLCipher, and refuses
98
+ rather than store plain text when expo-sqlite is built without it.
99
+ - **Observability**: `db:open`, `db:transaction` and `db:slowQuery` (with `slowQueryMs`) events, and
100
+ `db.diagnostics()` for the storage queue depth.
101
+ - **`anchordb/testing`**: `fakeExpoSqlite` and `fakeCapacitorSqlite` run the real adapters in Node,
102
+ and `runAdapterConformance` holds any adapter to the storage contract. The Expo stand-in is the
103
+ expense-tracker team's, which found the 1.3.2 bugs.
104
+ - **Default file name**: an Expo or Capacitor adapter built without a name takes the database's —
105
+ `new ExpoSqliteAdapter({ sqlite })` with `name: "expense-tracker"` opens `expense-tracker.db`.
106
+ - `anchordb-react`: **`useAnchorStatus(db)`** documented as the way to render opening, failure and retry.
107
+ - **Guides in the package**, under `docs/`: sync, concurrency and transactions, migrations / recovery
108
+ / TTL / encryption, aggregation, testing, the inspector. Sync existed since 1.0 but was never
109
+ explained, which is why the team built their own.
110
+ - **Every package ships this changelog**, and each release is tagged on GitHub.
111
+
112
+ ### Changed
113
+
114
+ - Every storage adapter queues all of its calls, reads included, per database. Concurrency was already
115
+ safe for writes in 1.3.3; reads now also never see another caller's uncommitted transaction.
116
+ - An error from `open()` is now a `DatabaseOpenError` (message prefixed "The database did not open:")
117
+ instead of the driver's bare error, which is kept as `cause`. Code that matched on the message still
118
+ finds it inside.
119
+ - `node:sqlite` adapter: prepared statements are dropped when the schema changes. One planned against
120
+ a partial index inside a transaction otherwise kept that plan and matched nothing when reused.
121
+
122
+ ### Not yet
123
+
124
+ - Sync on a timer: `autoSync` and `intervalMs` are still reserved; call `db.sync.now()`.
125
+ - Suspense for `useFind`; server-side expiry of sync delete markers; transactions on IndexedDB.
126
+
127
+ ## 1.3.3
128
+
129
+ **Writes through Expo and Capacitor SQLite are safe under concurrency, and work on a device.** Found
130
+ in an expense tracker on 1.3.2; every case below has a regression test.
131
+
132
+ - **Concurrent writes no longer share a transaction** (Expo, Capacitor). Every driver call awaits each
133
+ statement, so two writes started together interleaved, and the second ran inside the first's
134
+ transaction: a write reported as failed could be partly saved, and one caller's rollback could undo
135
+ another's committed write. `SqlAdapterBase` now queues every driver call, reads included.
136
+ - **Expo SQLite writes no longer fail with `database is locked`.** Inside
137
+ `withExclusiveTransactionAsync` statements now go to the `txn` connection expo-sqlite hands over,
138
+ instead of the outer one the exclusive lock blocks. Apps that mapped the exclusive transaction onto
139
+ `withTransactionAsync` as a workaround keep working.
140
+ - **Concurrent upserts of the same new key** now insert once and update the rest, as MongoDB 4.2+ does,
141
+ instead of rejecting with E11000. A duplicate on some other unique field is still reported.
142
+ - **A failed `db.open()` can be retried.** The rejection was cached, so a transient failure needed a
143
+ new `AnchorDB`.
144
+ - **Duplicate-key errors name the configured database** — `expense-tracker.metas`, not
145
+ `anchor.metas`. `ExpoSqliteAdapter` defaults its name to the file name without `.db`, and
146
+ `createAnchorDB` passes `config.name`.
147
+ - `anchordb-react`: **`useAnchorReady` no longer waits forever when the database fails to open.** It
148
+ throws the error during render, for an error boundary. The new `useAnchorStatus(db)` returns
149
+ `{ status, ready, error, retry }` to show the failure and retry in place, and `anchorOpenStore(db)`
150
+ is the store both read. Neither starts work while rendering any more.
151
+
152
+ ## 1.3.2
153
+
154
+ Documentation only — no code changes.
155
+
156
+ - **Bugs, support and feedback go to the AnchorDB project page**, at
157
+ [nisalanadeera.com/projects/anchordb](https://www.nisalanadeera.com/projects/anchordb#feedback): a form
158
+ that asks for the package, version and platform, and a reply by email.
159
+ - Every package's npm **Homepage** is that page, and **Report a bug** (`npm bugs`) opens the form.
160
+ - Every README links the overview and the form, and says what a bug report that can be acted on
161
+ includes.
162
+ - The package READMEs' family tables list all six packages, with `anchordb-lens-link`.
163
+ - All six packages move to 1.3.2 together.
164
+
165
+ ## 1.3.1
166
+
167
+ **Lens Link keeps both apps running in the background.** Found on a phone: switching from the app to
168
+ Anchor Lens let the phone stop the app within seconds, and the link went with it.
169
+
170
+ - `anchordb-lens-link`: while the link is on, the app runs an Android foreground service with an
171
+ ongoing notification — *Anchor Lens Link on*, then *Anchor Lens connected* — which is what Android
172
+ lets an app use to keep running. `keepAlive: false` turns it off; `link.keepAliveError` says why it
173
+ could not start.
174
+ - `startKeepAlive`, `updateKeepAlive` and `stopKeepAlive` keep a client running the same way. Anchor
175
+ Lens uses them while it is connected to an app, so you can switch between the two.
176
+ - `backgroundStatus()`, `askNotificationPermission()`, `askBatteryUnrestricted()`,
177
+ `openNotificationSettings()` and `openBackgroundSettings()`: the permissions and settings that stop a
178
+ phone overruling it, including Xiaomi's Autostart screen.
179
+ - Only `anchordb-lens-link` changes. The other packages stay at 1.3.0.
180
+
181
+ ## 1.3.0
182
+
183
+ **Anchor Lens Link: open a QA build's database in Anchor Lens on the same phone, from a file.** Asked
184
+ for after testing on a phone, where reaching another app took a laptop, the relay, an address, a room, a
185
+ QR scan and a pairing code.
186
+
187
+ - **New package, `anchordb-lens-link`.** `enableLensLink(db, { allowInProduction: true })` starts a
188
+ WebSocket server on 127.0.0.1, puts an `InspectorAgent` behind it and writes a sealed
189
+ `Android/media/<package>/anchor-lens/<database>.anchorlens`. In Anchor Lens, *Open app from file*
190
+ reads it, connects and authenticates with nothing typed. The port and the secret change every
191
+ launch. Android only; the native part is a small Expo module on Java-WebSocket. It is a separate
192
+ package, and does nothing unless the app calls it, so production apps need never ship it.
193
+ - **`auth.sharedSecret` for the inspector.** An agent can authenticate a secret both sides already
194
+ hold instead of a code shown on screen. It is proved the same way, as an HMAC over a single-use
195
+ challenge, but it is not burned, so a client can reconnect; a spent or expired challenge is replaced
196
+ at once. Secrets shorter than 32 characters are refused. Pairing codes work as before.
197
+ - **`assertInspectorAllowed` is exported**, so a package that starts an agent applies the same
198
+ production guard as the relay connection.
199
+ - Tested in Node end to end: the sealed file, an agent with a shared secret behind a WebSocket server
200
+ that behaves like the native one, and a Lens client that reads the file, proves the secret, reads and
201
+ writes through the Model API, reconnects with the same file, and is shut out after `close()`.
202
+
203
+ ## 1.2.0
204
+
205
+ Anchor Lens can create and drop indexes, and a malformed `_id` is refused instead of stored. Both
206
+ found while testing Lens on a phone.
207
+
208
+ - **Create Index and Drop Index on the inspector protocol.** `InspectorClient.createIndex(collection,
209
+ key, options)` and `dropIndex(collection, name)`, routed through `Model.createIndex()` and
210
+ `dropIndex()`. Agents had advertised `indexes:write` with no method behind it. Keys are checked
211
+ (`1` or `-1`, no `$` fields), read-only sessions refuse both, a unique index over values that already
212
+ collide fails with `duplicate_key`, and `_id_` cannot be dropped.
213
+ - **`getSchema(collection)` on the inspector protocol** — a declared model's fields with their type,
214
+ required flag, enum and plain default, nested objects as dotted paths. What Lens needs to offer
215
+ "Add all fields" on Insert document. Validator functions and function defaults are not sent; a
216
+ collection with no declared model returns no fields.
217
+ - **An insert stored an object `_id` as "[object Object]".** Insert skipped the `_id` handling updates
218
+ apply, and storage keys rows by the id's string form — so Extended JSON pasted into Lens, with
219
+ `{ "$oid": … }` read as a plain object, produced such a row, and every such document would have
220
+ collided on it. Objects that are not ObjectIds are now refused with a `CastError`. Strings and
221
+ numbers are kept, as the driver keeps them.
222
+
223
+ ## 1.1.0
224
+
225
+ **Anchor Lens can read other apps.** Pointing Lens at a second app on a real phone found every step of
226
+ that path broken or missing.
227
+
228
+ - **`inspector: { enabled, relayUrl }` did nothing.** It ran a production check and never connected.
229
+ With `relayUrl` set the database now publishes itself to `anchor-relay` on construction, stays
230
+ connected, reconnects after a drop, and reports pairing codes through `inspector.onPairing` and the
231
+ `inspector:pairing` / `inspector:state` events. `db.inspector` exposes the connection, and
232
+ `connectInspectorToRelay(db, options)` does the same at runtime.
233
+ - **Pairing asked for a 32-character hex challenge, typed on a phone.** The agent now sends it with
234
+ `connect` as `ConnectResult.challenge` — a nonce, not a secret; the code never leaves the app — and
235
+ opens a fresh pairing window, announcing its code, when the last one was spent or expired. Lens types
236
+ only the code.
237
+ - **The production guard never fired on React Native.** It read `process.env.NODE_ENV` through
238
+ `globalThis`, which Metro does not inline, so a release build looked like development. `__DEV__ ===
239
+ false` now counts as production too.
240
+ - **`anchordb-relay`:**
241
+ - With `--host 0.0.0.0` it printed `ws://0.0.0.0:9440` — the listen address, which no device can
242
+ dial. It now prints the machine's network addresses.
243
+ - It prints the Lens link as a QR code in the terminal.
244
+ - `--room <id>` fixes the room, so an app built with the agent URL survives relay restarts.
245
+ - The room it printed was reclaimed after 30 idle minutes, so an app connecting later got "unknown
246
+ room". It is now kept for the life of the relay.
247
+ - Stopping it hung while an app or Lens was connected: neither `wss.close` nor `http.close` ends
248
+ established connections. They are now terminated.
249
+ - Tested over real sockets: a relay server, an app publishing with `connectInspectorToRelay`, and a Lens
250
+ client that pairs with only the code, reads and writes, then shuts down cleanly.
251
+
252
+ ## 1.0.6
253
+
254
+ Crash on launch in React Native apps that load `anchordb` before `anchordb-react`.
255
+
256
+ - **Importing `anchordb` needed a crypto source.** `ObjectId` drew its per-process random block and
257
+ its counter seed when the module loaded. On React Native, `globalThis.crypto` comes from the
258
+ `react-native-get-random-values` polyfill that `anchordb-react` loads — so an app that evaluated
259
+ `anchordb` first died with `No cryptographically secure random source is available` before it
260
+ generated a single id. Lens React did exactly that through a re-export and closed the instant it
261
+ launched on a phone; the Contacts app survived only because its first import happened to be
262
+ `createAnchorDB`. Both values are now drawn on the first `ObjectId`, and a failed draw caches
263
+ nothing, so a polyfill that loads later still works.
264
+ - The error message now points React Native users at `anchordb-react`'s `createAnchorDB`.
265
+ - A new test imports the whole package with no crypto source. Without this fix it fails with the
266
+ original error.
267
+
268
+ ## 1.0.5
269
+
270
+ Inspector fix, found by building Anchor Lens on a database on the device.
271
+
272
+ - **Schemaless collections were reported to Lens as schema-backed.** `db.collection(name)` — which
273
+ the inspector agent uses for any collection without a model, including every collection Lens
274
+ creates by inserting into it — registers an internal `__collection__<name>` model.
275
+ `getCollections` counted it as a schema, so Lens showed `hasSchema: true` and a model pill reading
276
+ `__collection__notes` instead of "schemaless". The agent now reports only models the app declared.
277
+ - **`modelForCollection` returned whichever model registered first.** A collection reached through
278
+ `db.collection()` before its model was declared resolved to the schemaless model, so an export
279
+ emitted ObjectIds and Dates as bare strings. A declared model now always wins.
280
+
281
+ ## 1.0.4
282
+
283
+ `anchordb-angular` in native Capacitor builds. No change to database behaviour.
284
+
285
+ - **Capacitor links native plugins only from the package.json of the app.** `@capacitor-community/sqlite`
286
+ arrives through `anchordb-angular`, so it was installed but `npx cap sync` left it out of the
287
+ Android project — found by building the Ionic test app, whose `capacitor.settings.gradle` had no
288
+ SQLite plugin. On a device the first query would have failed with
289
+ `"CapacitorSQLite" plugin is not implemented on android`. `ionicAdapter` now checks
290
+ `Capacitor.isPluginAvailable("CapacitorSQLite")` and throws naming
291
+ `npm install @capacitor-community/sqlite` and `npx cap sync`. It does not fall back to IndexedDB,
292
+ which would strand the data in a store the app abandons once the plugin is linked.
293
+ - **`@capacitor/core` was declared `^8.5.2` and `@capacitor-community/sqlite` `^8.1.1`** — the same
294
+ `npm install -w` caret rewrite as `anchordb-react` 1.0.1. A Capacitor 6 or 7 app would have got a
295
+ second `@capacitor/core`, and plugins registered on one instance are invisible to the other. Both
296
+ are now `>=6`, held by a regression test.
297
+ - The README and package reference showed `inject(AnchorService)` and `AnchorModule.forRoot(...)`
298
+ inside `imports`. Neither works: the providers use string tokens, and `forRoot` returns plain
299
+ providers. Both now show `@Inject("AnchorService")` and spread `.providers`.
300
+ - Verified in the Ionic test app on Capacitor 8.5.2: with the plugin listed, `cap sync` reports
301
+ `@capacitor-community/sqlite@8.1.1` for Android and the Gradle settings include it.
302
+
303
+ ## 1.0.3
304
+
305
+ Guidance fix for Expo apps. No change to database behaviour.
306
+
307
+ - **`createAnchorDB` and the `anchordb-react` README recommended `npx expo install --fix`**, which
308
+ cannot help: it only realigns packages listed in the package.json of the app, and `expo-sqlite`
309
+ and `react-native-get-random-values` arrive through `anchordb-react`. Both now name
310
+ `npx expo install expo-sqlite react-native-get-random-values`, which pins the drivers at the top
311
+ level where the wide ranges from 1.0.2 dedupe onto them.
312
+ - Verified in an Expo SDK 56 app: with the pins, both drivers resolve to the versions the SDK pins
313
+ (`expo-sqlite` 56.0.6, `react-native-get-random-values` 1.11.0), deduped, and
314
+ `npx expo install --check` reports dependencies up to date. Without the pin the polyfill resolves
315
+ to 2.0.0 against the 1.11 native module Expo Go ships.
316
+
317
+ ## 1.0.2
318
+
319
+ `anchordb-react` pinned its native drivers to a single Expo SDK.
320
+
321
+ - **`expo-sqlite` was declared `^57.0.3`**, so an app on Expo SDK 56 (`expo-sqlite ~56.0.4`) could
322
+ not dedupe it. npm nested a second, SDK 57 `expo-sqlite` whose JavaScript no longer matched the
323
+ native build of the app. The intended range was `>=14`; `npm install -w` rewrote it with a caret
324
+ when the dependency was added. Both drivers now take wide ranges (`expo-sqlite >=14`,
325
+ `react-native-get-random-values >=1.11`), so npm reuses whatever version the Expo SDK of the app
326
+ already installed.
327
+ - A test now asserts both ranges accept the drivers Expo SDK 56 and 57 ship and are not caret- or
328
+ tilde-pinned, so a future `npm install -w` cannot silently narrow them again.
329
+
330
+ Found by comparing against a working Expo SDK 56 app on the same machine.
331
+
332
+ ## 1.0.1
333
+
334
+ Two defects in `anchordb-angular`, both in its *documented* usage, found by building a real Ionic
335
+ app against the published package for the first time.
336
+
337
+ - **The provider arrays did not typecheck against Angular.** `Provider.useFactory` was declared
338
+ optional, so the array was not assignable to Angular’s `Provider[]` and the documented
339
+ `bootstrapApplication` example failed to compile. It is now required, matching what every
340
+ provider in the package actually returns, and `useValue` — declared but never used — is gone.
341
+ - **`.toObservable()` was documented but implemented nowhere.** The real API is
342
+ `AnchorService.find$` / `findOne$` / `count$`, which return an RxJS-interop `AnchorObservable`
343
+ the `async` pipe accepts directly. The documentation now shows that.
344
+
345
+ ## 1.0.0
346
+
347
+ **Versioning changes with this release.** The major version now tracks the React / Angular major the
348
+ packages are built against: React 18 stays on the `0.x` line, React 19 begins at `1.x`. Projects on
349
+ React 18 remain on 0.2.1, preserved on the
350
+ [`release/0.x-react18`](https://github.com/knnadeera/anchordb/tree/release/0.x-react18) branch.
351
+
352
+ ### One install, ready to use
353
+
354
+ `npm install anchordb-react` now brings the database, the SQLite driver and the crypto polyfill —
355
+ and `createAnchorDB({ name })` needs no adapter wiring. `npm install anchordb-angular` does the
356
+ same, with `provideAnchorIonic` choosing Capacitor SQLite on a device and IndexedDB under
357
+ `ionic serve`.
358
+
359
+ - `anchordb-react` gains `createAnchorDB`, and depends on `expo-sqlite` and
360
+ `react-native-get-random-values`
361
+ - `anchordb-angular` gains `ionicAdapter` and `provideAnchorIonic`, and depends on
362
+ `@capacitor/core` and `@capacitor-community/sqlite`
363
+
364
+ ### Breaking
365
+
366
+ - **`anchordb-react` is now React Native only.** It imports `react-native-get-random-values`, which
367
+ imports React Native internals, so a React web build fails. Browser apps use `anchordb` directly
368
+ with `anchordb/storage/indexeddb`, which is unchanged.
369
+ - **React 19 is required** by `anchordb-react`, since `expo-sqlite` pulls React Native.
370
+
371
+ ### Fixed
372
+
373
+ - **Subpath imports were unusable under `moduleResolution: Node10`.** Neither `anchordb` nor
374
+ `anchordb-sync-server` declared `typesVersions`, so `anchordb/storage/expo-sqlite` and friends
375
+ resolved to nothing for any consumer on classic resolution — and broke this repo's own CommonJS
376
+ build. Every `node10` result in are-the-types-wrong is now green where most were previously
377
+ failing.
378
+ - **The `ExpoDatabase` interface did not match the real `expo-sqlite`.** `params` was declared
379
+ optional where the driver requires it, and typed `unknown[]` where SQLite accepts only five bind
380
+ types. The actual module was therefore not assignable to the interface, so every TypeScript user
381
+ following the documented usage got an error. Caught by typechecking against the real package for
382
+ the first time.
383
+ - **`sideEffects: false` on `anchordb-react`** would have let a bundler tree-shake away the crypto
384
+ polyfill, making the first `ObjectId` throw. It now names the built entries.
385
+
386
+ ## 0.2.1
387
+
388
+ Documentation and discoverability only — no code changes.
389
+
390
+ - Every package README now carries a **The AnchorDB family** table, so someone landing on
391
+ `anchordb-react` from an npm search can see the other four and what each is for.
392
+ - npm keywords added to `anchordb-react`, `anchordb-angular`, `anchordb-sync-server` and
393
+ `anchordb-relay`, which had none and so did not surface in npm search at all. `anchordb` gained
394
+ aggregation, schema and document-database terms.
395
+ - Corrected stale `0.1.0` version claims in three READMEs.
396
+
397
+ ## 0.2.0 — first published release
398
+
399
+ Published as the unscoped `anchordb` family. The `@anchor` scope was never available: it needs an
400
+ npm organization, so the packages took unscoped names instead.
401
+
402
+ ### Added
403
+
404
+ - **Bulk writes on the inspector protocol** — `updateMany` and `deleteMany`, behind a new
405
+ `documents:bulk` capability, routed through the ordinary Model API so a bulk write from Anchor
406
+ Lens validates, stamps and queues exactly like an app write. An empty filter is refused unless
407
+ explicitly acknowledged.
408
+ - **CSV export and import** (`toCsv`, `fromCsv`, `detectImportFormat`), matching
409
+ `mongoexport --type=csv`. Values are cast through the collection schema on import.
410
+ - **A `filter` option on export**, for exporting query results rather than a whole collection.
411
+ - **A `default` Extended JSON mode**, alongside `relaxed` and `canonical`.
412
+ - **A MongoDB bridge** (`MongoBridgeClient` here, `MongoBridge` in `anchordb-relay`), so Lens can
413
+ pull collections from a real MongoDB or push a device into one.
414
+
415
+ ### Fixed
416
+
417
+ - **`modifiedCount` could never be 0.** `updatedAt` and the version key were stamped before the
418
+ change comparison, so every matched document counted as modified and a no-op still bumped the
419
+ timestamp. A no-op update is now matched but not modified, and writes nothing — which also stops a
420
+ bulk update over 10,000 documents queueing 10,000 mutations when only a few hundred changed.
421
+ - **`MongooseStore` was never exported** from `anchordb-sync-server`, so it was absent from the
422
+ published types and unreachable by anyone following the README.
423
+
424
+ ## 0.1.0 — never published
425
+
426
+ The initial implementation. Superseded by 0.2.0 before anything reached npm.
427
+
428
+ First release. Five packages, published together.
429
+
430
+ ### `anchordb`
431
+
432
+ - **Local-first database** with a Mongoose-shaped API. No `sync` block means a purely local
433
+ database: no mutation queue, no network code, no sync metadata, hard deletes.
434
+ - **Mongoose parity**: `Schema`, `model()`, documents with `.save()`/`.isModified()`, virtuals,
435
+ methods, statics, `pre`/`post` hooks, `ValidationError`/`CastError` shapes, and `code: 11000`.
436
+ - **Decorators** (`anchordb/decorators`) matching `@nestjs/mongoose` — `@Schema`, `@Prop`,
437
+ `SchemaFactory`, `raw()` — so one decorated class can be shared with a NestJS backend.
438
+ Metadata is optional: explicit `@Prop(String)` works with `emitDecoratorMetadata` off.
439
+ - **Real MongoDB ObjectId**, generated on-device, cross-validated byte-for-byte against `bson`.
440
+ - **Indexes** — single, compound, multikey, `unique`, `sparse`, `partialFilterExpression`, TTL —
441
+ with unique violations enforced at the storage layer and reported as `E11000`.
442
+ - **Lazy chainable query builder**: `.populate().sort().skip().limit().select().exec()`, thenable,
443
+ async-iterable, with `explain()`.
444
+ - **Aggregation pipeline** with streaming execution, index pushdown, and a `mongoCompatible` strict
445
+ mode that rejects non-portable constructs at development time.
446
+ - **UTC-canonical timestamps** with IANA timezone support, validated at construction.
447
+ - **Extended JSON v2 interop** — `export()` feeds `mongoimport`; `mongoexport` output imports back.
448
+ - **Offline mutation queue** and sync engine with five conflict strategies
449
+ (`last-write-wins`, `server-wins`, `client-wins`, `field-level`, `custom`).
450
+ - **Inspector protocol v1** with pairing, sessions, and live change events.
451
+ - **Five storage adapters**: Memory, Node SQLite, IndexedDB, Expo SQLite, Capacitor SQLite.
452
+
453
+ ### `anchordb-sync-server`
454
+
455
+ - Framework-agnostic protocol engine over a pluggable `ServerStore`.
456
+ - Express, NestJS and Next.js adapters, all held to one conformance suite.
457
+ - `MemoryStore` (default) and `MongooseStore`.
458
+
459
+ ### `anchordb-react`
460
+
461
+ - `useFind`, `useFindOne`, `useCount`, `useAggregate`, `useSyncStatus`, `useAnchorEvent`.
462
+
463
+ ### `anchordb-angular`
464
+
465
+ - `AnchorModule.forRoot`/`forFeature`, `getModelToken`, `AnchorService` with RxJS-compatible
466
+ observables. Angular and RxJS are optional peers and are never imported.
467
+
468
+ ### `anchordb-relay`
469
+
470
+ - Development-only WebSocket relay plus the `anchor-relay` CLI.
471
+
472
+ ### Known limitations
473
+
474
+ - **Expo SQLite and Capacitor SQLite are unverified** — written and typechecked, never executed on
475
+ a device. Test before production use.
476
+ - The REST sync transport and `MongooseStore` have no live-server tests.
477
+ - Not supported in v1: discriminators, `refPath`, transactions, server-side change streams,
478
+ text/geo/hashed indexes, collation, and the `$graphLookup`/`$geoNear`/`$search`/`$merge`/`$out`/
479
+ `$unionWith` aggregation stages.
package/README.md CHANGED
@@ -133,6 +133,12 @@ Each one needs a different third-party framework as a peer dependency, and npm r
133
133
  package rather than per import — which is why they are not one package. Full reasoning and API
134
134
  reference: [github.com/knnadeera/anchordb](https://github.com/knnadeera/anchordb).
135
135
 
136
+ ## Changes
137
+
138
+ What changed in each version is in [CHANGELOG.md](./CHANGELOG.md), shipped in this package — one
139
+ changelog for the whole family, since all six packages are released together. Releases are also
140
+ tagged on [GitHub](https://github.com/knnadeera/anchordb/releases).
141
+
136
142
  ## Bugs, support and feedback
137
143
 
138
144
  Report a bug, ask for help or suggest a feature on the [AnchorDB project page](https://www.nisalanadeera.com/projects/anchordb#feedback) —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anchordb-angular",
3
- "version": "1.3.3",
3
+ "version": "1.4.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -23,7 +23,8 @@
23
23
  "files": [
24
24
  "dist",
25
25
  "README.md",
26
- "LICENSE"
26
+ "LICENSE",
27
+ "CHANGELOG.md"
27
28
  ],
28
29
  "scripts": {
29
30
  "build": "rimraf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.build.cjs.json && node ../core/scripts/finalize-dist.mjs",
@@ -34,7 +35,7 @@
34
35
  "dependencies": {
35
36
  "@capacitor-community/sqlite": ">=6",
36
37
  "@capacitor/core": ">=6",
37
- "anchordb": "^1.3.3"
38
+ "anchordb": "^1.4.1"
38
39
  },
39
40
  "devDependencies": {
40
41
  "rimraf": "^6.0.1"