memorio 4.7.3 → 4.8.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/README.md +206 -0
- package/SUMMARY.md +7 -0
- package/index.cjs +68 -60
- package/index.d.ts +1 -0
- package/index.js +23 -14
- package/markdown/MEMORY-ATTACHMENT.md +95 -0
- package/markdown/SQLITE.md +181 -0
- package/markdown/SYNC.md +170 -0
- package/package.json +9 -3
- package/types/exports.d.ts +2 -0
- package/types/memorio.d.ts +29 -0
- package/types/memory.d.ts +57 -0
- package/types/sqlite.d.ts +35 -0
package/README.md
CHANGED
|
@@ -67,6 +67,9 @@ npm i memorio
|
|
|
67
67
|
|
|
68
68
|
# Optional - only if you use the React hook
|
|
69
69
|
npm i react react-dom
|
|
70
|
+
|
|
71
|
+
# Optional - only if you want a local sql.js for `sqlite` (default uses CDN)
|
|
72
|
+
npm i sql.js
|
|
70
73
|
```
|
|
71
74
|
|
|
72
75
|
---
|
|
@@ -160,6 +163,88 @@ const user = await idb.data.get('my-db', 'users', 1)
|
|
|
160
163
|
|
|
161
164
|
> IndexedDB is a browser-only primitive - see [Cross-Platform Behavior](#cross-platform-behavior) for what happens off the browser.
|
|
162
165
|
|
|
166
|
+
### `sqlite` - in-memory SQLite, zero config
|
|
167
|
+
|
|
168
|
+
`memorio.sqlite` is an optional, lazily-loaded SQLite engine backed by [`sql.js`](https://sql.js.org) (the optional `sql.js` npm package is **not** a build-time dependency). It runs entirely in memory — ideal for ad-hoc SQL, structured queryable data, and local relational lookups. The engine is fetched on first use and never loaded when you don't touch `sqlite`.
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import 'memorio' // or: import { sqlite } from 'memorio'
|
|
172
|
+
|
|
173
|
+
await sqlite.ready // waits until the sql.js engine is loaded (or rejected)
|
|
174
|
+
sqlite.db.support() // true when the current platform can run sql.js
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Bases (databases) are addressed by name, like `idb`:
|
|
178
|
+
const SQL = await sqlite.db.getSQL() // the underlying sql.js engine (loaded once, cached)
|
|
179
|
+
sqlite.db.version() // engine version string, or null before load
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Bases (databases) are addressed by name, like `idb`. `sqlite.db.create('app')` opens (or creates) an in-memory database, while `sqlite.db.get('app')` retrieves an already-open handle (`sqlite.db.list/delete/size` round out the lifecycle):
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
await sqlite.db.create('app') // in-memory database handle
|
|
186
|
+
await sqlite.query.run('app', 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
|
|
187
|
+
``` `sqlite.data` gives a small shortcut layer, and `sqlite.query` runs SQL:
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// Write (shortcut over raw prepare/bind)
|
|
191
|
+
await sqlite.data.set('app', 'users', { id: 1, name: 'Sara' })
|
|
192
|
+
await sqlite.data.get('app', 'users', 1) // { id: 1, name: 'Sara' }
|
|
193
|
+
|
|
194
|
+
// SQL
|
|
195
|
+
await sqlite.query.run('app', 'CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)')
|
|
196
|
+
const rows = await sqlite.query.select('app', 'SELECT * FROM items', [1])
|
|
197
|
+
|
|
198
|
+
// Portability: export / import a whole base as a binary blob
|
|
199
|
+
const blob = await sqlite.db.export('app')
|
|
200
|
+
await sqlite.db.import('app', blob)
|
|
201
|
+
|
|
202
|
+
// Clean up
|
|
203
|
+
await sqlite.db.delete('app')
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Loading the engine
|
|
207
|
+
|
|
208
|
+
The default loader injects the sql.js UMD build (`sql-wasm-browser.js`) from the
|
|
209
|
+
jsDelivr CDN as a classic `<script>`; on load it exposes the `initSqlJs` factory
|
|
210
|
+
on `globalThis`, which memorio then calls with your `locateFile`. This avoids a
|
|
211
|
+
bare `import('sql.js')` so bundlers never resolve the optional `sql.js`
|
|
212
|
+
dependency at build time:
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
// Zero config: CDN <script> loader (default)
|
|
216
|
+
await sqlite.ready
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
If you prefer a local/bundled `sql.js` (offline, private network, or to pin a
|
|
220
|
+
version), install it and supply your own loader:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npm i sql.js # optional peer
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
import { sqlite } from 'memorio'
|
|
228
|
+
|
|
229
|
+
sqlite.config({ loader: () => import('sql.js') }) // local/npm build of sql.js
|
|
230
|
+
await sqlite.ready
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
You can also point the WASM `locateFile` step at your own CDN/base via
|
|
234
|
+
`sqliteWasmBase` on `globalThis`, or pass a custom `locateFile` through
|
|
235
|
+
`sqlite.config({ locateFile })`:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
globalThis.sqliteWasmBase = 'https://your-cdn.example.com/sql.js/dist/'
|
|
239
|
+
sqlite.config({ locateFile: (file) => `https://your-cdn.example.com/sql.js/dist/${file}` })
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
When the engine can't load (e.g. no WASM support), `sqlite.ready` rejects, `sqlite._disabled` becomes `true`, and `sqlite._warning` explains why — `db.support()` simply returns `false` so you can degrade gracefully.
|
|
243
|
+
|
|
244
|
+
- `sqlite.config({ persistence: true })` / `sqlite.db.create('app', { persistence: true })` snapshot a database to `store` (localStorage, namespaced) and restore it on reopen — sql.js databases are in-memory by default; see [SQLite docs – Persistence & dev download](markdown/SQLITE.md#example-5-persistence--dev-download).
|
|
245
|
+
|
|
246
|
+
See [SQLite docs](markdown/SQLITE.md) for the full reference.
|
|
247
|
+
|
|
163
248
|
### `observer` / `useObserver` - watch a path, react to it
|
|
164
249
|
|
|
165
250
|
```javascript
|
|
@@ -403,6 +488,126 @@ See [Memory docs](markdown/MEMORY.md) for full reference.
|
|
|
403
488
|
|
|
404
489
|
---
|
|
405
490
|
|
|
491
|
+
## Synchronization & Cloud (optional)
|
|
492
|
+
|
|
493
|
+
`memorio.memory` is **local-first**. The data is created and served from the
|
|
494
|
+
device; the cloud is only ever a **transport/persistence provider**, never the
|
|
495
|
+
source of truth. Enabling sync does not replace local storage — it *mirrors* it.
|
|
496
|
+
|
|
497
|
+
```
|
|
498
|
+
memorio
|
|
499
|
+
│
|
|
500
|
+
┌────────┴────────┐
|
|
501
|
+
│ Memory Engine │
|
|
502
|
+
└────────┬────────┘
|
|
503
|
+
┌────────────┼────────────┐
|
|
504
|
+
▼ ▼ ▼
|
|
505
|
+
local SQLite cloud
|
|
506
|
+
memory durable sync
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Configuring a backend
|
|
510
|
+
|
|
511
|
+
Sync is **opt-in**. You supply an application-owned `provider` that knows how to
|
|
512
|
+
talk to your backend (REST, WebSocket, Supabase, a custom agent server, a PostgreSQL
|
|
513
|
+
database, etc.). **Memorio never handles credentials** — authentication and
|
|
514
|
+
authorization live in your backend/provider (OWASP A01: Broken Access Control):
|
|
515
|
+
|
|
516
|
+
```ts
|
|
517
|
+
memorio.memory.configure({
|
|
518
|
+
namespace: 'user:123:device:abc', // tenant/user/device — partitions the journal
|
|
519
|
+
provider: { // application-owned transport
|
|
520
|
+
push(ops) { return fetch('/api/sync', { method: 'POST', body: JSON.stringify(ops), headers: auth }) }
|
|
521
|
+
pull(since) { return fetch(`/api/sync?since=${since}`).then(r => r.json()) }
|
|
522
|
+
},
|
|
523
|
+
auto: true // auto-replay pending ops on focus/online (default true)
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
await memorio.memory.ready // waits until the local journal substrate is chosen
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Once configured, `memorio.memory` records every operation locally and keeps it
|
|
530
|
+
until the provider acknowledges it.
|
|
531
|
+
|
|
532
|
+
### The local journal
|
|
533
|
+
|
|
534
|
+
Every mutation (`remember`, `update`, `forget`, `expire`, `confirm`, `supersede`)
|
|
535
|
+
is written to a local, **namespaced** operation journal:
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
await memory.remember('user.language', 'Italian', { scope: 'local' })
|
|
539
|
+
|
|
540
|
+
memory.journal.pending() // -> [{ id, key:'user.language', value:'Italian', operation:'remember', sync:'pending', version: 1, updatedAt: ... }]
|
|
541
|
+
memory.journal.markSynced([id])
|
|
542
|
+
memory.journal.replay() // pushes pending() to provider.provider, marks synced, optional pull+apply
|
|
543
|
+
memory.journal.status() // 'sqlite' | 'store' (substrate in use)
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
The journal stores the full entry plus `operation`, `version`, `updatedAt` and
|
|
547
|
+
`sync` status, so conflicts can be resolved when connectivity returns.
|
|
548
|
+
|
|
549
|
+
### Substrates
|
|
550
|
+
|
|
551
|
+
The journal is persisted on `store` (localStorage / in-memory Map fallback) — **not** on a sql.js database, because sql.js databases are volatile (in-memory) and would lose pending operations on reload:
|
|
552
|
+
|
|
553
|
+
| Substrate | Used for | Notes |
|
|
554
|
+
|---|---|---|
|
|
555
|
+
| `store` (localStorage) | sync journal | persistent across reloads; namespaced; Map fallback in Node |
|
|
556
|
+
| `sqlite` (sql.js) | ad-hoc SQL / value storage | in-memory by default — use `persistence: true` to snapshot to `store` |
|
|
557
|
+
| `idb` (IndexedDB) | `memorio.memory` durable scope values | persistent; persistent across reloads |
|
|
558
|
+
|
|
559
|
+
The `sqlite.db.download(name)` dev helper also triggers a browser `.sqlite` download of an in-memory database on demand.
|
|
560
|
+
|
|
561
|
+
### Sync = operations, not database dumps
|
|
562
|
+
|
|
563
|
+
Memorio syncronizza **operazioni di memoria**, never a raw database dump. When
|
|
564
|
+
two devices diverge, conflict resolution is based on `confidence`,
|
|
565
|
+
`lastConfirmedAt`, `source`, `version` and `scope` — not just "last write wins":
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
// Device A: user.language = Italian, confidence 0.92
|
|
569
|
+
// Device B: user.language = English, confidence 0.61
|
|
570
|
+
// → the higher-confidence entry wins locally; the provider decides for shared.
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
The `namespace` (tenant / user / device) is the single partition key: local
|
|
574
|
+
journal reads and writes are scoped to it, and they can never cross namespaces —
|
|
575
|
+
a client holding a fake/forged namespace simply sees its own empty journal.
|
|
576
|
+
|
|
577
|
+
### Scopes (isolation, not a security boundary)
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
scope: 'device' // only this browser/device
|
|
581
|
+
scope: 'user' // follows the user across devices (via sync)
|
|
582
|
+
scope: 'shared' // shared across users/tenant
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
`scope: 'user'`/`'shared'` require a provider + namespace. `scope: 'device'`
|
|
586
|
+
is local only. As with `memorio.createContext`, **scoping is a naming convention,
|
|
587
|
+
not a security boundary** — enforce real isolation in your backend.
|
|
588
|
+
|
|
589
|
+
### Security posture
|
|
590
|
+
|
|
591
|
+
- **NIST SP 800-53 / OWASP**: no credentials, tokens, or secrets are read from or
|
|
592
|
+
stored by `memorio`; sensitive state you place in `state`/`store`/`session`/`idb`
|
|
593
|
+
is not encrypted by memorio (see [Security](#security)).
|
|
594
|
+
- **Namespace isolation**: journal reads/writes are keyed by
|
|
595
|
+
`namespace:id` at the storage layer; there is no API to enumerate or open
|
|
596
|
+
another namespace's journal (defense-in-depth).
|
|
597
|
+
- **No dynamic code**: journal entries are strictly JSON-round-tripped and
|
|
598
|
+
size-capped (10 MB/entry); no `eval`/template-injection of provider data.
|
|
599
|
+
- **Trust boundary**: the provider/backend owns authentication, authorization,
|
|
600
|
+
and remote-side conflict resolution. Memorio owns the local durable copy and
|
|
601
|
+
the operation log; it surfaces `conflict`/`error` rows via `journal.pending()`.
|
|
602
|
+
- **NSA/CISA advice (data-at-rest/secrets)**: if you persist `state`/`store`
|
|
603
|
+
server-side or ship user data through your backend, encrypt it server-side with
|
|
604
|
+
keys you manage; memorio treats the local journal as untrusted-from-the-browser
|
|
605
|
+
and does not attest its own integrity.
|
|
606
|
+
|
|
607
|
+
See [SQLite docs](markdown/SQLITE.md), [Memory docs](markdown/MEMORY.md), and the [Synchronization & Cloud guide](markdown/SYNC.md).
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
406
611
|
## Cross-Platform Behavior
|
|
407
612
|
|
|
408
613
|
memorio runs everywhere JavaScript does - but "everywhere" means different guarantees in different places, and we'd rather tell you now than have you find out at 2am:
|
|
@@ -415,6 +620,7 @@ memorio runs everywhere JavaScript does - but "everywhere" means different guara
|
|
|
415
620
|
| `store` | `localStorage` | `Map` fallback - **not durable across restarts** | `Map` fallback - not durable | `localStorage` where available, else `Map` |
|
|
416
621
|
| `session` | `sessionStorage` | `Map` fallback - not durable | `Map` fallback - not durable | `sessionStorage` where available, else `Map` |
|
|
417
622
|
| `idb` | ✅ `IndexedDB` | ❌ not available | ❌ not available | ⚠️ check `getCapabilities()` |
|
|
623
|
+
| `sqlite` | ✅ `sql.js` (lazy, CDN by default) | ❌ not available | ❌ not available | ⚠️ check `sqlite.db.support()` |
|
|
418
624
|
| `devtools` | ✅ | ❌ | ❌ | ⚠️ |
|
|
419
625
|
|
|
420
626
|
Same API top to bottom - that's the promise. But if your server code leans on `store.get(...)` surviving a redeploy, know that on Node/Deno it won't; the fallback is an in-memory cache with the same shape, not durable storage.
|
package/SUMMARY.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* [Store](markdown/STORE.md) - Persistent localStorage management
|
|
13
13
|
* [Session](markdown/SESSION.md) - Temporary sessionStorage management
|
|
14
14
|
* [IDB](markdown/IDB.md) - IndexedDB for large data storage
|
|
15
|
+
* [SQLite](markdown/SQLITE.md) - SQLite in the browser via sql.js (WASM)
|
|
15
16
|
|
|
16
17
|
## Typed & Validated
|
|
17
18
|
|
|
@@ -26,6 +27,12 @@
|
|
|
26
27
|
## Memory System
|
|
27
28
|
|
|
28
29
|
* [Memory](markdown/MEMORY.md) - Semantic memory layer with TTL, confidence, scopes
|
|
30
|
+
* [Node Attachment](markdown/MEMORY-ATTACHMENT.md) - Dynamic node attachment system
|
|
31
|
+
|
|
32
|
+
## Experimental
|
|
33
|
+
|
|
34
|
+
* [Memory Substrates Benchmark](experimental/memory-substrates/BENCHMARK.md) - Protocol for evaluating runtime substrates
|
|
35
|
+
* [Leak Detection](experimental/memory-substrates/LEAK-DETECTION.md) - Tooling & methods for memory leak analysis
|
|
29
36
|
|
|
30
37
|
## Platform & Compatibility
|
|
31
38
|
|