memorio 5.1.1 → 5.1.3

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/AGENTS.md CHANGED
@@ -69,9 +69,7 @@ If the code you're generating is client-side (a single browser tab, one user), `
69
69
  outside a guaranteed browser context must guard: `if (idb.db.support())` or check
70
70
  `memorio.getCapabilities().hasIndexedDB` - don't rely on the no-op warning alone reaching a log
71
71
  anyone will see.
72
- - **`sqlite` persistence serializes the entire database on every flush** - not incremental. Never
73
- generate code that calls a persisting write inside a loop; batch writes in one transaction/run
74
- and persist once after the batch, per the README's guidance.
72
+ - **`sqlite` persistence uses journal + checkpoint (incremental writes, periodic full snapshots).** Batch writes and persist once after the batch per the README's guidance — calling `persist()` inside a tight loop still forces expensive checkpoints.
75
73
  - **`observer('state.some.path', cb)` paths are plain strings, unchecked against `state`'s actual
76
74
  shape.** A typo or a later rename fails *silently* - the observer just never fires again. Prefer
77
75
  `memorio.typed<T>()` + `registerSchema()` for anything you'd hate to have silently stop working,
package/CHANGELOG.md ADDED
@@ -0,0 +1,80 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+ - **SQLite journal + checkpoint persistence**: When `persistence: true` is set on `sqlite.db.create()` (or via `sqlite.config({ persistence: true })`), writes are recorded in an append-only journal with HLC timestamps. Periodic checkpoints (every 50 ops or 250 ms of write-idle) snapshot the full database to `store`. On reopen, the checkpoint is loaded and pending journal entries are replayed — no writes lost between checkpoints. New methods: `sqlite.db.flush()`, `sqlite.db.persist()`, `sqlite.db.journal` namespace (`append`, `entries`, `count`, `clear`, `replay`, `checkpoint`), `sqlite.db.journal` for direct journal inspection.
9
+
10
+ ## [5.1.2] - 2026-09-14
11
+
12
+ ### Fixed
13
+ - **`types/encryption.d.ts`**: Fixed parse error (`TS1005: ',' expected`) in `deriveKey` signature — missing comma after `alg` parameter caused all consumers' type checkers to fail, even with `skipLibCheck: true`.
14
+ - **`core/platform.ts`**: `_isBun()` now checks `typeof globalAny.Bun.version === 'string'` instead of `typeof globalAny.Bun.sqlite === 'function'`, correctly detecting the Bun runtime so `hasBunSqlite()` returns `true` and the `bun:sqlite` backend loads.
15
+ - **`functions/sqlite/tools/bun-sqlite-adapter.ts`**: Removed unused `_index` variable.
16
+ - **`functions/security/index.ts`**: Removed redundant type re-export block that conflicted with inline `export type`/`export interface` declarations under `isolatedModules`.
17
+ - **`extension/vscode/src/astIndexer.ts`**: Removed unused imports (`path`, `StateUsage`, `StatePathInfo`, `StoreOperation`) and unused `lines`/`program` parameters.
18
+ - **`extension/vscode/esbuild.config.mjs`**: Replaced TypeScript type annotations with JSDoc `/** @type */` to fix parse errors in `.mjs` context.
19
+
20
+ ### Packaging
21
+ - **`package.json`**: Changed `"sideEffects": true` to `"sideEffects": ["./global.js", "./global.cjs"]` so tree-shaking works for consumers using only `state`/`store` — previously the entire engine (SQLite, memory, encryption) was bundled unconditionally.
22
+ - Added `types/bun-sqlite.d.ts` module declaration so `import('bun:sqlite')` resolves under TypeScript.
23
+
24
+ ### Migration guide: globals change (v5 breaking change)
25
+
26
+ **Upgrading from 4.x:** the globals (`state`, `store`, `session`, `cache`, `idb`, `observer`, `useObserver`) are no longer installed by `import "memorio"`. Applications that use them without importing them must change one line:
27
+
28
+ ```ts
29
+ // 4.x — globals installed on import
30
+ import 'memorio'
31
+
32
+ // 5.x — globals installed via the global entrypoint
33
+ import 'memorio/global'
34
+ ```
35
+
36
+ Nothing else changes. The named imports (`import { state } from 'memorio'`) work identically.
37
+
38
+ **Bundler cache:** after upgrading, restart the dev server and clear `node_modules/.vite` (Vite) or `.next/cache` (Next.js), because a stale pre-bundle can mask the breakage — the app may appear to work and then fail at the next dependency re-optimisation.
39
+
40
+ ## [5.1.0] - 2026-09-12
41
+
42
+ ### Added
43
+ - **Bun runtime support**: `memorio.isBun()` and `memorio.getCapabilities().hasBunSqlite` for runtime detection alongside `isBrowser()`/`isNode()`/`isDeno()`/`isEdge()`.
44
+ - **`bun:sqlite` backend**: SQLite operations under Bun use the native `bun:sqlite` binding - no WASM, real incremental writes, no full-database serialization on flush. Falls back to `sql.js` (browser) where Bun sqlite is unavailable. No changes to consumers: the same `sqlite.db.create()`, `sqlite.query.run()`, `sqlite.query.select()` APIs work unchanged.
45
+ - **Bun dev toolchain**: `bunfig.toml`, `test:bun`, `build:bun`, `lint:bun`, `tsc:bun` scripts. Existing `npm`/`npx` scripts remain as fallbacks. `bun` added to `devDependencies` only (not `dependencies`/`peerDependencies`).
46
+ - **`security.sanitizeValue()`**: recursive sanitization with HTML entity decode, URL decode, XSS scheme blocking, and `__proto__`/`constructor`/`prototype` key stripping.
47
+ - **`security.RBAC`**: `addAccessRule()`, `hasPermission()` with regex/function patterns, fail-closed by default when no rule matches.
48
+ - **`security.audit logging`**: `setAuditLogger()`, `logAudit()`, `isAuditActive()`. `hasPermission()` auto-logs denied attempts when an audit logger is configured.
49
+ - **`computed` module**: lazy-memoized derived state with dependency tracking (`compute()`, `getValue()`, `subscribe()`, `remove()`, `list()`, `clear()`).
50
+ - **`broadcast` module**: cross-tab sync via `BroadcastChannel` + `storage` event fallback (`install()`, `uninstall()`, `isInstalled()`).
51
+ - **PBKDF2 600k iterations** (NIST SP 800-132), up from 100k. `deriveKey()` accepts `iterations` parameter.
52
+ - **`encryption.exportKey()` / `encryption.importKey()`**: base64 key export/import with length validation.
53
+ - **`store.config()` / `session.config()`**: accept `onError`, `maxObjectSize`, `maxTotalSize` alongside existing `encryptionKey`.
54
+
55
+ ### Security
56
+ - PBKDF2 key derivation upgraded to 600,000 iterations (NIST SP 800-132 recommendation).
57
+ - `sanitizeValue` now strips dangerous URL schemes (`javascript:`, `vbscript:`, `data:text/html`, `about:blank`, `chrome:`) without word-boundary requirements, catching encoded variants like `%6javascript:`.
58
+ - `sanitizeValue` now handles `<object>`, `<embed>`, `<svg>`, `<iframe>`, `<script>` tag removal including void elements and nested payloads.
59
+ - `sanitizeValue` skips `__proto__`, `constructor`, `prototype` keys to prevent prototype pollution.
60
+ - `encryption.importKey()` validates AES-256 key length (32 bytes) and throws descriptive error for truncated input.
61
+ - RBAC `hasPermission()` fail-closed: no matching rule → denied + auto-audit-logged.
62
+ - `AuditEntry.action` type extended to include `'read'`, `'write'`, `'admin'`, `'permission_check'`.
63
+
64
+ ### Documentation
65
+ - README restyled: tagline "The memory layer for AI agents and apps - owned by the user, not the vendor."
66
+ - README: "Application memory" section moved before "Global or explicit".
67
+ - README: "Skip this unless..." callout lines added to 10 skippable sections.
68
+ - README: layers table gained "When" column (Start here / Add later).
69
+ - README: Cross-platform table gained Bun column with `bun:sqlite` native support.
70
+ - README: Quick reading map added after Install.
71
+ - README: "This page covers everything... Most apps only need the first three sections." callout after first example.
72
+ - SECURITY.md: documented Web Crypto async/non-blocking behavior.
73
+ - SECURITY.md: PBKDF2 iteration count updated to 600k.
74
+ - SECURITY-HARDENING.md: checklist expanded to 16 items.
75
+ - CHANGELOG.md: this file.
76
+
77
+ ### Developer experience
78
+ - Lint check test (`lint-check.test.ts`) integrated into test suite.
79
+ - `tests/bun/` directory for Bun-specific tests (`bun:test` imports).
80
+ - `tests/vitest/tests/` for Node.js/Vitest tests (unchanged).
package/README.md CHANGED
@@ -63,6 +63,20 @@ npm install memorio
63
63
 
64
64
  Zero production dependencies in core. Optional integrations (`react`, `sql.js`, etc.) are installed only when you use them.
65
65
 
66
+ ### Globals migration (v5)
67
+
68
+ If you are upgrading from memorio 4.x and your code uses `state`, `store`, `session`, `cache`, `observer`, or `useObserver` as **bare globals** (without importing them), change one line:
69
+
70
+ ```ts
71
+ // 4.x
72
+ import 'memorio'
73
+
74
+ // 5.x
75
+ import 'memorio/global'
76
+ ```
77
+
78
+ Named imports (`import { state } from 'memorio'`) are unaffected. After upgrading, restart your dev server and clear `node_modules/.vite` / `.next/cache` to avoid stale pre-bundles masking the change. See [`markdown/IMPORT.md`](./markdown/IMPORT.md) for full details.
79
+
66
80
  ---
67
81
 
68
82
  ## Start here
@@ -148,7 +162,6 @@ For most apps, that's enough. Everything below is an optional capability you can
148
162
  ### Other
149
163
  | Topic | Reference |
150
164
  | --- | --- |
151
- | Version history | [`CHANGELOG.md`](./CHANGELOG.md) |
152
165
  | Working examples - each file has a `Run:` comment at the top (typically `npx ts-node examples/<name>.ts`, or `npx ts-node --esm examples/<name>.tsx` for React examples) | [`examples/`](./examples/) |
153
166
  | Architecture decisions | [`adr/`](./adr/) |
154
167
 
@@ -160,7 +173,7 @@ Memorio is upfront about what it doesn't do, so you don't find out the hard way:
160
173
 
161
174
  - **No encryption by default.** Data is stored in plain text unless you explicitly turn on `memorio.encryption` or pass an `encryptionKey`. See [`SECURITY.md`](./SECURITY.md).
162
175
  - **Namespaces/contexts aren't a security boundary.** `memorio.isolate()` gives you logical separation between tenants or sessions, not authorization or access control — enforce that at your application layer.
163
- - **SQLite persistence (`sql.js` backend) isn't incremental.** Each write exports and re-saves the whole database, which gets costly as data grows. The `bun:sqlite` backend avoids this cost but doesn't support `export()` at all — see [`markdown/SQLITE.md`](./markdown/SQLITE.md).
176
+ - **SQLite persistence uses a journal + checkpoint strategy.** Individual writes are recorded in an append-only journal (incremental); periodic checkpoints snapshot the full database. This avoids serializing the entire database on every write. The `bun:sqlite` backend doesn't support `export()` but handles persistence natively — see [`markdown/SQLITE.md`](./markdown/SQLITE.md).
164
177
  - **`memory.context()` is rule-based, not embedding-based.** It ranks structured entries by recency, confidence, and type — it does not do semantic similarity search. Pair it with a vector store if your agent needs "find things like this."
165
178
  - **Key management is your responsibility.** Memorio's encryption is client-side; it doesn't manage, rotate, or store keys for you.
166
179
 
package/SUMMARY.md CHANGED
@@ -17,7 +17,7 @@
17
17
  | `react-observer.tsx` | `useObserver` in due modalità (auto-discovery vs deps espliciti) combinato con `typed<T>()` e `registerSchema()`. |
18
18
  | `semantic-memory.ts` | Memoria applicativa per un'app LLM-backed: remember/update con confidence e source, retrieval con `memory.context()` - con nota esplicita che non è ricerca semantica per embedding. |
19
19
  | `session-advanced.ts` | Uso avanzato di `session`: auth token, bozza di form, carrello, dimensione dello storage. |
20
- | `sqlite-batched-writes.ts` | Come evitare di serializzare l'intero DB SQLite ad ogni riga: batch di insert seguito da un solo flush. |
20
+ | `sqlite-batched-writes.ts` | Con il journal+checkpoint, i write sono incrementali ma i checkpoint (snapshot completo) sono costosi: batch di insert seguito da un solo flush. |
21
21
  | `state-advanced.ts` | Stato annidato, array, locking di un valore (`.lock()`), path tracking, rimozione stato. |
22
22
  | `store-advanced.ts` | `store` avanzato: persistenza, quota, alias dei metodi, gestione errori, serializzazione di vari tipi. |
23
23
  | `sync.ts` *(nuovo)* | Local-first sync: configurazione di un `SyncProvider` (push/pull/resolve), scope `device`/`user`/`shared`, ispezione e replay del journal. |
@@ -47,7 +47,7 @@
47
47
  | `SCHEMA.md` | Validazione runtime dei percorsi di stato: schema oggetto/array/enum/funzione custom. |
48
48
  | `SECURITY.md` | Postura di sicurezza del progetto (minacce coperte, cosa NON fa Memorio, come viene gestito l'accesso ai dati). |
49
49
  | `SESSION.md` | Reference di `session` (sessionStorage) con fallback in-memory fuori dal browser. |
50
- | `SQLITE.md` | Reference del layer SQLite via `sql.js`: caricamento lazy, persistenza, query. |
50
+ | `SQLITE.md` | Reference del layer SQLite via `sql.js`/`bun:sqlite`: caricamento lazy, persistenza journal+checkpoint, query. |
51
51
  | `STATE.md` | Reference dello stato reattivo basato su Proxy - il layer centrale di Memorio. |
52
52
  | `STORE.md` | Reference di `store` (localStorage) con fallback in-memory fuori dal browser. |
53
53
  | `SYNC.md` | Sincronizzazione local-first opzionale: scope, journal, conflict resolution, strategie avanzate per multi-device (HLC, tombstones, fractional indexing). |
@@ -3,9 +3,10 @@
3
3
  *
4
4
  * Scenario: importing or writing many rows into memorio's sqlite layer.
5
5
  *
6
- * Persistence there serializes the ENTIRE database on every flush - not
7
- * incremental. Calling a persisting write inside a per-row loop is the
8
- * single most common way to accidentally make this layer slow.
6
+ * With persistence enabled, each write is recorded in an append-only journal
7
+ * (incremental). Periodic checkpoints — every 50 operations or 250 ms of
8
+ * write-idle — take a full database snapshot. Calling `flush()` inside a
9
+ * per-row loop triggers a checkpoint on every iteration, which is expensive.
9
10
  */
10
11
  import { memorio } from 'memorio'
11
12
 
@@ -24,14 +25,16 @@ export async function importUsers(users: UserRow[]) {
24
25
  `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, role TEXT)`
25
26
  )
26
27
 
27
- // Bad: this would serialize the whole DB after every single insert.
28
+ // Bad: this would trigger a full checkpoint after every single insert.
28
29
  //
29
30
  // for (const user of users) {
30
31
  // await memorio.sqlite.query.run('app', 'INSERT INTO users ...', [...])
31
32
  // await memorio.sqlite.db.flush('app') // <- don't do this per row
32
33
  // }
33
34
 
34
- // Good: run every insert first, persist once after the batch.
35
+ // Good: run every insert first, flush once after the batch. Writes are
36
+ // journaled incrementally (cheap); the checkpoint (full snapshot) happens
37
+ // once at the end.
35
38
  for (const user of users) {
36
39
  await memorio.sqlite.query.run(
37
40
  'app',
@@ -40,7 +43,7 @@ export async function importUsers(users: UserRow[]) {
40
43
  )
41
44
  }
42
45
 
43
- // Persist explicitly, once, after the whole batch - check the installed
46
+ // Flush explicitly, once, after the whole batch — check the installed
44
47
  // version's API for the exact flush/persist call name if it differs from
45
48
  // automatic persistence-on-close.
46
49
  const admins = await memorio.sqlite.query.select(
@@ -54,4 +57,4 @@ export async function importUsers(users: UserRow[]) {
54
57
 
55
58
  // For read-heavy or scratch-space use where durability doesn't matter,
56
59
  // skip { persistence: true } entirely - sqlite runs in memory by default,
57
- // which avoids the serialize cost altogether.
60
+ // which avoids journal and checkpoint overhead altogether.