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/llms.txt CHANGED
@@ -21,8 +21,8 @@ Memorio provides 6 storage modules plus utilities:
21
21
  | `session` | sessionStorage | Dies with browser tab; falls back to non-durable in-memory `Map` in Node.js/Deno |
22
22
  | `cache` | In-memory cache | Fastest read, no persistence |
23
23
  | `idb` | IndexedDB | Structured, async, persistent (browser-only - disabled in Node.js/Deno) |
24
- | `sqlite` | SQLite via sql.js (WebAssembly) | Browser-only relational SQL |
25
- | `observer` | Object watcher | Legacy; string-based paths, not statically checked against `state`'s shape |
24
+ | `sqlite` | SQLite via sql.js (WebAssembly) / `bun:sqlite` (native) | Browser-only relational SQL; optional journal + checkpoint persistence to `store` |
25
+ | `observer` | Object watcher | String-based path observer; use `typed<T>()` + `registerSchema()` for statically checked alternatives |
26
26
  | `useObserver` | React hook | Auto-discovery of state paths |
27
27
  | `encryption` | AES-GCM + PBKDF2 | Encrypt/decrypt values, store/session integration |
28
28
 
@@ -51,6 +51,8 @@ To opt in to global access (state, store, session, cache, idb, sqlite, observer,
51
51
  import 'memorio/global'
52
52
  ```
53
53
 
54
+ **Upgrading from 4.x:** in v5, `import 'memorio'` no longer installs globals on `globalThis`. If your code uses bare globals (e.g. `state.counter = 1` without importing `state`), change the import to `import 'memorio/global'`. 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.
55
+
54
56
  This is independent of bundler environment detection (no `import.meta.env.DEV`, no `process.env.NODE_ENV` checks).
55
57
 
56
58
  ## API Reference
@@ -1,10 +1,10 @@
1
- > **Status:** Published
2
- > **Date:** 2026-09-12
3
- > **Scope**: API Reference
4
- > **Standard**: Memorio API Specification v5
5
- >
6
- ---
7
- # SQLite - Memorio
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Scope**: API Reference
4
+ > **Standard**: Memorio API Specification v5
5
+ >
6
+ ---
7
+ # SQLite - Memorio
8
8
 
9
9
  > The `sql.js` package is **optional** - if it is not installed, Memorio loads `sql.js` on first use by injecting the `sql-wasm-browser.js` UMD build from the jsDelivr CDN as a classic `<script>` (which exposes the `initSqlJs` factory on `globalThis`). No bare `import('sql.js')` is ever emitted, so bundlers never resolve the optional dependency at build time. Not available in Node.js/Deno.
10
10
 
@@ -97,16 +97,16 @@ console.debug('SQLite version:', sqlite.db.version());
97
97
  ### Example 5: Persistence & dev download
98
98
 
99
99
  > **Important:** sql.js databases live in **WebAssembly memory** - they are
100
- > in-memory and **volatile** (lost on page refresh) unless you persist them.
100
+ > in-memory and **volatile** (lost on page refresh) unless you opt into persistence.
101
101
 
102
102
  ```javascript
103
- // Opt into auto-persistence at create time (global config or per-create)
103
+ // Opt into persistence at create time (global config or per-create)
104
104
  await sqlite.db.create('app', { persistence: true });
105
105
 
106
106
  await sqlite.query.run('app', 'CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT)');
107
- // writes are snapshotted to localStorage automatically (debounced via updateHook)
107
+ // writes are journaled incrementally; checkpoints are saved automatically
108
108
 
109
- await sqlite.db.persist('app'); // force an immediate snapshot
109
+ await sqlite.db.persist('app'); // force an immediate checkpoint (full snapshot + clear journal)
110
110
  // After a refresh, reopening restores the data:
111
111
  await sqlite.db.create('app', { persistence: true });
112
112
 
@@ -117,10 +117,33 @@ await sqlite.db.download('app', 'app.sqlite');
117
117
  await sqlite.db.close('app');
118
118
  ```
119
119
 
120
+ Persistence uses a **journal + checkpoint** strategy for incremental durability:
121
+
122
+ 1. **Journal**: every `db.run(sql, params)` write is recorded as a journal entry
123
+ (with an HLC timestamp for causal ordering) in `store` (localStorage). The
124
+ journal is append-only and incremental - only the changed statement is stored.
125
+ 2. **Checkpoint**: every 50 operations (configurable), or after 250 ms of write
126
+ idle, a full database snapshot is taken and written to `store`. The journal is
127
+ then cleared up to that point.
128
+ 3. **Recovery**: on `create(name, { persistence: true })`, the latest checkpoint
129
+ is loaded first, then any journal entries that were written after the
130
+ checkpoint are replayed on top - so no writes are lost even if the page closes
131
+ between checkpoints.
132
+
120
133
  Persistence is stored on `store` (localStorage, namespaced per
121
- `sqlite.config({ namespace })` / memorio context) as a base64 snapshot under
122
- `memorio:sqlite:db:<ns>:<name>`. It is best-effort: if `store` is unavailable
123
- the database simply behaves as in-memory.
134
+ `sqlite.config({ namespace })` / memorio context) as:
135
+ - Checkpoint: `memorio:sqlite:db:<ns>:<name>` (base64 binary snapshot)
136
+ - Journal entries: `memorio:sqlite:journal:<ns>:<name>:<seq>` (individual SQL ops)
137
+
138
+ It is best-effort: if `store` is unavailable the database simply behaves as
139
+ in-memory. The journal is also available directly:
140
+
141
+ ```javascript
142
+ sqlite.db.persist('app'); // force checkpoint (alias: flush)
143
+ sqlite.db.flush('app'); // force checkpoint
144
+ const entries = sqlite.db.journal.entries('app'); // inspect pending ops
145
+ await sqlite.db.journal.checkpoint('app'); // manual checkpoint
146
+ ```
124
147
 
125
148
  ---
126
149
 
@@ -132,9 +155,11 @@ the database simply behaves as in-memory.
132
155
  |--------|------------|---------|-------------|
133
156
  | `sqlite.config(opts)` | `opts: { loader?, locateFile?, wasmUrl?, persistence?, namespace? }` | `sqlite` | Configure the engine. `loader` fully replaces the initializer (default = CDN `<script>`); `locateFile` customizes wasm resolution; `wasmUrl` sets the wasm base directory; `persistence` toggles automatic db snapshots; `namespace` partitions persisted snapshots. Chainable. |
134
157
  | `sqlite.db.create(name, opts)` | `name: string, opts?: { data?, persistence? }` | `Database` | Opens/creates a named in-memory db. With `persistence: true` (or global config), a snapshot is restored if present and writes are auto-saved. |
135
- | `sqlite.db.persist(name)` | `name: string` | `Promise<boolean>` | Force an immediate snapshot of a persisted database to `store`. |
158
+ | `sqlite.db.persist(name)` | `name: string` | `Promise<boolean>` | Force an immediate checkpoint (full snapshot + journal clear) of a persisted database to `store`. Alias of `flush`. |
159
+ | `sqlite.db.flush(name)` | `name: string` | `Promise<boolean>` | Force an immediate checkpoint (alias of `persist`). |
136
160
  | `sqlite.db.download(name, filename?)` | `name: string, filename?: string` | `Promise<boolean>` | Dev-only: trigger a browser download of the db as a `.sqlite` file. |
137
- | `sqlite.db.close(name)` | `name: string` | `Promise<void>` | Persist (if enabled), close, and release the handle. |
161
+ | `sqlite.db.close(name)` | `name: string` | `Promise<void>` | Checkpoint (if enabled), close, and release the handle. |
162
+ | `sqlite.db.journal` | `name: string` | Object | Journal namespace: `append`, `entries`, `count`, `clear`, `replay`, `checkpoint`. |
138
163
  | `sqlite.ready` | none | `Promise<void>` | Resolves once `sql.js` has been initialized. Rejects (and sets `_disabled`) if the engine can't load. |
139
164
  | `sqlite.db.version()` | none | `string \| null` | Engine version, available after initialization. |
140
165
  | `sqlite._disabled` | none | `boolean` | `true` when the module is disabled (non-browser env / load failure). |
@@ -147,7 +172,7 @@ the database simply behaves as in-memory.
147
172
  | `sqlite.db.support()` | none | `boolean` | Check whether SQLite can run in this environment. |
148
173
  | `sqlite.db.create(name, opts?)` | `name: string`, `opts?: { data }` | `Promise<Database>` | Create an in-memory database (or reopen one from a binary dump). |
149
174
  | `sqlite.db.get(name)` | `name: string` | `Database` | Retrieve an open database handle. |
150
- | `sqlite.db.delete(name)` | `name: string` | `boolean` | Close and remove a database handle. |
175
+ | `sqlite.db.delete(name)` | `name: string` | `Promise<boolean>` | Checkpoint (if enabled), close, and remove a database handle. |
151
176
  | `sqlite.db.list()` | none | `string[]` | List open database names. |
152
177
  | `sqlite.db.size(name?)` | `name?: string` | `Promise<number>` | Size in bytes of one or all databases. |
153
178
  | `sqlite.db.export(name)` | `name: string` | `Promise<Uint8Array>` | Export a database to a binary dump. |
@@ -184,6 +209,7 @@ the database simply behaves as in-memory.
184
209
 
185
210
  1. Configure the wasm path for production: `sqlite.config({ wasmUrl })` or `sqlite.config({ loader })`.
186
211
  2. Create one named database per feature and reuse the handle: `const db = await sqlite.db.create('app')`.
187
- 3. Always release databases you no longer need: `sqlite.db.delete('temp')`.
188
- 4. Use `await sqlite.ready` before running statements to ensure the engine is loaded.
189
- 5. Use `?` placeholders and `params` to avoid SQL injection.
212
+ 3. Use `await sqlite.ready` before running statements to ensure the engine is loaded.
213
+ 4. Use `?` placeholders and `params` to avoid SQL injection.
214
+ 5. Batch writes and call `sqlite.db.persist()` / `sqlite.db.flush()` once after the batch, not inside a loop. The journal captures each write incrementally, but the checkpoint (full snapshot) is the expensive operation.
215
+ 6. Always release databases you no longer need: `await sqlite.db.delete('temp')`.
package/markdown/STORE.md CHANGED
@@ -1,10 +1,10 @@
1
- > **Status:** Published
2
- > **Date:** 2026-09-12
3
- > **Scope**: API Reference
4
- > **Standard**: Memorio API Specification v5
5
- >
6
- ---
7
- # Store - Memorio
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Scope**: API Reference
4
+ > **Standard**: Memorio API Specification v5
5
+ >
6
+ ---
7
+ # Store - Memorio
8
8
 
9
9
  > 🖥️ **Browser & Edge**: Uses localStorage for persistence
10
10
  > ⚙️ **Node.js/Deno**: Falls back to in-memory storage (not persistent)
@@ -56,7 +56,7 @@ store.remove('username');
56
56
 
57
57
  // Check size
58
58
  const totalSize = store.size();
59
- console.debug(`${totalSize} bytes`);
59
+ console.debug(`${totalSize} KB`);
60
60
  ```
61
61
 
62
62
  ### Example 3: Advanced
@@ -66,9 +66,9 @@ console.debug(`${totalSize} bytes`);
66
66
  const [used, total] = await store.quota();
67
67
  console.debug(`Using ${used} out of ${total} KB`);
68
68
 
69
- // Get total size in characters
69
+ // Get total size in kilobytes
70
70
  const size = store.size();
71
- console.debug(`${size} bytes`);
71
+ console.debug(`${size} KB`);
72
72
 
73
73
  // Clear all data
74
74
  store.removeAll();
@@ -97,7 +97,7 @@ try {
97
97
  | `store.delete(name)` | `name: string` | `boolean` | Alias for remove |
98
98
  | `store.removeAll()` | none | `boolean` | Clear all storage |
99
99
  | `store.clearAll()` | none | `boolean` | Alias for removeAll |
100
- | `store.size()` | none | `number` | Get total size in characters |
100
+ | `store.size()` | none | `number` | Get total size in kilobytes (KB) |
101
101
  | `store.quota()` | none | `Promise<[number, number]>` | Get storage usage/quota in KB |
102
102
 
103
103
  ### Properties
@@ -167,4 +167,4 @@ Use `store.quota()` to monitor usage.
167
167
  1. Prefix keys: `store.set('app_username', '...')`
168
168
  2. Check before set: `if (store.get('key')) { ... }`
169
169
  3. Handle quota: Try/catch around large data
170
- 4. Clean up: `store.removeAll()` on logout
170
+ 4. Clean up: `store.removeAll()` on logout
package/markdown/SYNC.md CHANGED
@@ -1,10 +1,10 @@
1
- > **Status:** Published
2
- > **Date:** 2026-09-12
3
- > **Scope**: API Reference
4
- > **Standard**: Memorio API Specification v5
5
- >
6
- ---
7
- # Synchronization & Cloud (optional)
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Scope**: API Reference
4
+ > **Standard**: Memorio API Specification v5
5
+ >
6
+ ---
7
+ # Synchronization & Cloud (optional)
8
8
 
9
9
  `memorio.memory` is **local-first**. Data is created and served from the device;
10
10
  the cloud is only ever a **transport/persistence provider**, never the source of
@@ -67,12 +67,15 @@ memorio.memory.configure({ sync: { provider: myCloudProvider, namespace: '…' }
67
67
  SQLite (`sql.js`) is **in-memory by default** (volatie per page load). It becomes
68
68
  the durable journal/value store when you opt in:
69
69
 
70
- - `sqlite.config({ persistence: true })` / `sqlite.db.create('app', { persistence: true })`
71
- snapshot the database to `store` (localStorage) and restore it on reopen.
72
- - Writes are snapshotted via sql.js `updateHook` (debounced).
73
- - `sqlite.db.persist(name)` forces an immediate save; `sqlite.db.close(name)`
74
- flushes + closes; `sqlite.db.download(name, file?)` triggers a browser
75
- `.sqlite` download (dev convenience).
70
+ - `sqlite.config({ persistence: true })` / `sqlite.db.create('app', { persistence: true })`
71
+ snapshot the database to `store` (localStorage) and restore it on reopen.
72
+ - Writes are journaled incrementally (append-only, HLC-timestamped) and
73
+ checkpointed periodically (every 50 ops or 250 ms of idle). On reopen, the
74
+ last checkpoint is loaded and the journal is replayed — no writes are lost.
75
+ - `sqlite.db.persist(name)` / `sqlite.db.flush(name)` forces an immediate
76
+ checkpoint; `sqlite.db.close(name)` checkpoints + closes;
77
+ `sqlite.db.download(name, file?)` triggers a browser `.sqlite` download
78
+ (dev convenience).
76
79
 
77
80
  See `docs/markdown/SQLITE.md` for the full SQLite reference.
78
81
 
@@ -172,7 +175,7 @@ interface SyncProvider {
172
175
  | `localStorage` / Map | `store` | no | yes (browser) |
173
176
  | `sessionStorage` / Map | `session` | no | per-tab (browser) |
174
177
  | IndexedDB | `idb`, `memory` durable | no | yes |
175
- | sql.js (WASM heap) | `sqlite` | **yes** | only with `persistence: true` (snapshot → `store`) |
178
+ | sql.js (WASM heap) | `sqlite` | **yes** | with `persistence: true` (journal + checkpoint → `store`) |
176
179
  | sync journal | `memory.journal` | no | yes (`store`) |
177
180
 
178
181
  ---
@@ -315,4 +318,4 @@ entity-level entries. Mitigate with:
315
318
  Applying granular path-level patches, HLC for causality, fractional indexing
316
319
  for ordered collections, explicit tombstones for deletions, and a convergence
317
320
  test suite lets memorio handle high-frequency concurrent offline edits across
318
- devices without the overhead of a full CRDT stack.
321
+ devices without the overhead of a full CRDT stack.
package/modules/redux.cjs CHANGED
@@ -471,8 +471,6 @@ var CONTEXTS_KEY, _contexts;
471
471
  var init_platform = __esm({
472
472
  "core/platform.ts"() {
473
473
  init_cjs_shims();
474
- init_internal();
475
- init_encryption();
476
474
  __name(getSessionStorage, "getSessionStorage");
477
475
  __name(getLocalStorage, "getLocalStorage");
478
476
  __name(hasIndexedDB, "hasIndexedDB");
@@ -1675,12 +1673,8 @@ function encodeHLC(hlcValue) {
1675
1673
  }
1676
1674
  __name(encodeHLC, "encodeHLC");
1677
1675
 
1678
- // core/mutation/patch.ts
1679
- init_cjs_shims();
1680
-
1681
1676
  // core/mutation/transaction.ts
1682
1677
  init_cjs_shims();
1683
- init_internal();
1684
1678
  var TX_REGISTRY_KEY = "__memorio_transaction_registry__";
1685
1679
  var registry = globalThis[TX_REGISTRY_KEY] || /* @__PURE__ */ new Map();
1686
1680
  if (!globalThis[TX_REGISTRY_KEY]) {