memorio 5.1.2 → 5.1.4
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 +1 -3
- package/CHANGELOG.md +83 -0
- package/README.md +32 -14
- package/SUMMARY.md +2 -2
- package/examples/sqlite-batched-writes.ts +60 -57
- package/global.cjs +454 -242
- package/global.js +431 -218
- package/index.cjs +454 -242
- package/index.js +431 -218
- package/llms.txt +17 -2
- package/markdown/MEMORY.md +27 -0
- package/markdown/SQLITE.md +48 -22
- package/markdown/STORE.md +12 -12
- package/markdown/SYNC.md +18 -15
- package/modules/redux.cjs +29 -12
- package/modules/redux.cjs.map +1 -1
- package/modules/redux.js +29 -12
- package/modules/redux.js.map +1 -1
- package/package.json +7 -2
- package/types/sqlite.d.ts +58 -35
- package/types/state.d.ts +19 -5
- package/vsix/memorio.vsix +0 -0
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
|
|
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,83 @@
|
|
|
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
|
+
### Fixed
|
|
11
|
+
- **`package.json` `sideEffects`**: Added `./core/global.ts` to the `sideEffects` array so that esbuild/tsup no longer tree-shakes the `import './core/global'` side-effect-only import in `index.ts`. Without this fix, the `core/global.ts` initialization block (which defines `globalThis.memorio`) was eliminated from production builds, causing `memorio.global()` to throw `Cannot read properties of undefined (reading 'global')`.
|
|
12
|
+
|
|
13
|
+
## [5.1.2] - 2026-09-14
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **`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`.
|
|
17
|
+
- **`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.
|
|
18
|
+
- **`functions/sqlite/tools/bun-sqlite-adapter.ts`**: Removed unused `_index` variable.
|
|
19
|
+
- **`functions/security/index.ts`**: Removed redundant type re-export block that conflicted with inline `export type`/`export interface` declarations under `isolatedModules`.
|
|
20
|
+
- **`extension/vscode/src/astIndexer.ts`**: Removed unused imports (`path`, `StateUsage`, `StatePathInfo`, `StoreOperation`) and unused `lines`/`program` parameters.
|
|
21
|
+
- **`extension/vscode/esbuild.config.mjs`**: Replaced TypeScript type annotations with JSDoc `/** @type */` to fix parse errors in `.mjs` context.
|
|
22
|
+
|
|
23
|
+
### Packaging
|
|
24
|
+
- **`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.
|
|
25
|
+
- Added `types/bun-sqlite.d.ts` module declaration so `import('bun:sqlite')` resolves under TypeScript.
|
|
26
|
+
|
|
27
|
+
### Migration guide: globals change (v5 breaking change)
|
|
28
|
+
|
|
29
|
+
**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:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// 4.x - globals installed on import
|
|
33
|
+
import 'memorio'
|
|
34
|
+
|
|
35
|
+
// 5.x - globals installed via the global entrypoint
|
|
36
|
+
import 'memorio/global'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Nothing else changes. The named imports (`import { state } from 'memorio'`) work identically.
|
|
40
|
+
|
|
41
|
+
**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.
|
|
42
|
+
|
|
43
|
+
## [5.1.0] - 2026-09-12
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
- **Bun runtime support**: `memorio.isBun()` and `memorio.getCapabilities().hasBunSqlite` for runtime detection alongside `isBrowser()`/`isNode()`/`isDeno()`/`isEdge()`.
|
|
47
|
+
- **`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.
|
|
48
|
+
- **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`).
|
|
49
|
+
- **`security.sanitizeValue()`**: recursive sanitization with HTML entity decode, URL decode, XSS scheme blocking, and `__proto__`/`constructor`/`prototype` key stripping.
|
|
50
|
+
- **`security.RBAC`**: `addAccessRule()`, `hasPermission()` with regex/function patterns, fail-closed by default when no rule matches.
|
|
51
|
+
- **`security.audit logging`**: `setAuditLogger()`, `logAudit()`, `isAuditActive()`. `hasPermission()` auto-logs denied attempts when an audit logger is configured.
|
|
52
|
+
- **`computed` module**: lazy-memoized derived state with dependency tracking (`compute()`, `getValue()`, `subscribe()`, `remove()`, `list()`, `clear()`).
|
|
53
|
+
- **`broadcast` module**: cross-tab sync via `BroadcastChannel` + `storage` event fallback (`install()`, `uninstall()`, `isInstalled()`).
|
|
54
|
+
- **PBKDF2 600k iterations** (NIST SP 800-132), up from 100k. `deriveKey()` accepts `iterations` parameter.
|
|
55
|
+
- **`encryption.exportKey()` / `encryption.importKey()`**: base64 key export/import with length validation.
|
|
56
|
+
- **`store.config()` / `session.config()`**: accept `onError`, `maxObjectSize`, `maxTotalSize` alongside existing `encryptionKey`.
|
|
57
|
+
|
|
58
|
+
### Security
|
|
59
|
+
- PBKDF2 key derivation upgraded to 600,000 iterations (NIST SP 800-132 recommendation).
|
|
60
|
+
- `sanitizeValue` now strips dangerous URL schemes (`javascript:`, `vbscript:`, `data:text/html`, `about:blank`, `chrome:`) without word-boundary requirements, catching encoded variants like `%6javascript:`.
|
|
61
|
+
- `sanitizeValue` now handles `<object>`, `<embed>`, `<svg>`, `<iframe>`, `<script>` tag removal including void elements and nested payloads.
|
|
62
|
+
- `sanitizeValue` skips `__proto__`, `constructor`, `prototype` keys to prevent prototype pollution.
|
|
63
|
+
- `encryption.importKey()` validates AES-256 key length (32 bytes) and throws descriptive error for truncated input.
|
|
64
|
+
- RBAC `hasPermission()` fail-closed: no matching rule → denied + auto-audit-logged.
|
|
65
|
+
- `AuditEntry.action` type extended to include `'read'`, `'write'`, `'admin'`, `'permission_check'`.
|
|
66
|
+
|
|
67
|
+
### Documentation
|
|
68
|
+
- README restyled: tagline "The memory layer for AI agents and apps - owned by the user, not the vendor."
|
|
69
|
+
- README: "Application memory" section moved before "Global or explicit".
|
|
70
|
+
- README: "Skip this unless..." callout lines added to 10 skippable sections.
|
|
71
|
+
- README: layers table gained "When" column (Start here / Add later).
|
|
72
|
+
- README: Cross-platform table gained Bun column with `bun:sqlite` native support.
|
|
73
|
+
- README: Quick reading map added after Install.
|
|
74
|
+
- README: "This page covers everything... Most apps only need the first three sections." callout after first example.
|
|
75
|
+
- SECURITY.md: documented Web Crypto async/non-blocking behavior.
|
|
76
|
+
- SECURITY.md: PBKDF2 iteration count updated to 600k.
|
|
77
|
+
- SECURITY-HARDENING.md: checklist expanded to 16 items.
|
|
78
|
+
- CHANGELOG.md: this file.
|
|
79
|
+
|
|
80
|
+
### Developer experience
|
|
81
|
+
- Lint check test (`lint-check.test.ts`) integrated into test suite.
|
|
82
|
+
- `tests/bun/` directory for Bun-specific tests (`bun:test` imports).
|
|
83
|
+
- `tests/vitest/tests/` for Node.js/Vitest tests (unchanged).
|
package/README.md
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/memorio)
|
|
6
6
|
[](./LICENSE)
|
|
7
|
-
[](https://bundlephobia.com/package/memorio)
|
|
8
7
|
[](https://socket.dev/npm/package/memorio)
|
|
9
8
|
[](https://snyk.io/test/npm/memorio)
|
|
10
9
|
[](#security)
|
|
@@ -13,14 +12,10 @@
|
|
|
13
12
|

|
|
14
13
|

|
|
15
14
|

|
|
16
|
-

|
|
17
15
|
[](#license)
|
|
18
16
|
|
|
19
|
-
<!--
|
|
20
|
-
[](https://github.com/GITHUB_ORG/GITHUB_REPO/actions)
|
|
21
|
-
-->
|
|
22
17
|
|
|
23
|
-
**The memory layer for AI agents and apps
|
|
18
|
+
**The memory layer for AI agents and apps - owned by the user, not the vendor.**
|
|
24
19
|
|
|
25
20
|
```ts
|
|
26
21
|
import 'memorio/global'
|
|
@@ -41,13 +36,13 @@ Just data, available where your application needs it.
|
|
|
41
36
|
|
|
42
37
|
That's the whole API for the simple case. No provider tree, no boilerplate.
|
|
43
38
|
|
|
44
|
-
But real apps grow. Most AI-powered apps (and most apps in general) eventually need more than "just state"
|
|
39
|
+
But real apps grow. Most AI-powered apps (and most apps in general) eventually need more than "just state" - persistence, session data, caches, structured browser storage, local SQL, application memory, history, optional sync. Usually that means pulling in a different library - and a different mental model - for each. Memorio gives them one consistent runtime, without making the simple case complicated:
|
|
45
40
|
|
|
46
41
|
```ts
|
|
47
42
|
state.value = 42
|
|
48
43
|
```
|
|
49
44
|
|
|
50
|
-
But the reason memorio exists isn't just "fewer dependencies." It's this: **the memory an AI agent builds about a user shouldn't be locked inside a vendor's server, opaque, and impossible to inspect or move.** Memorio's memory layer is structured, inspectable, editable, and
|
|
45
|
+
But the reason memorio exists isn't just "fewer dependencies." It's this: **the memory an AI agent builds about a user shouldn't be locked inside a vendor's server, opaque, and impossible to inspect or move.** Memorio's memory layer is structured, inspectable, editable, and - when you turn on encryption - readable only with a key the vendor doesn't hold. It runs client-side, in the browser, on the edge, or in Node.
|
|
51
46
|
|
|
52
47
|
That said, this covers *structured* memory - preferences, decisions, facts with confidence and provenance - not semantic similarity search. If your agent needs "find things like this conversation," pair memorio with a dedicated vector store; see [`markdown/MEMORY.md`](./markdown/MEMORY.md).
|
|
53
48
|
|
|
@@ -63,6 +58,20 @@ npm install memorio
|
|
|
63
58
|
|
|
64
59
|
Zero production dependencies in core. Optional integrations (`react`, `sql.js`, etc.) are installed only when you use them.
|
|
65
60
|
|
|
61
|
+
### Globals migration (v5)
|
|
62
|
+
|
|
63
|
+
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:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// 4.x
|
|
67
|
+
import 'memorio'
|
|
68
|
+
|
|
69
|
+
// 5.x
|
|
70
|
+
import 'memorio/global'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
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.
|
|
74
|
+
|
|
66
75
|
---
|
|
67
76
|
|
|
68
77
|
## Start here
|
|
@@ -70,17 +79,27 @@ Zero production dependencies in core. Optional integrations (`react`, `sql.js`,
|
|
|
70
79
|
Three things cover most apps - reactive state, persistence, and observation:
|
|
71
80
|
|
|
72
81
|
```ts
|
|
73
|
-
import { state,
|
|
82
|
+
import { state, observer } from 'memorio'
|
|
74
83
|
|
|
75
84
|
state.user = { name: 'Sara' }
|
|
76
85
|
|
|
77
|
-
persist('state.user')
|
|
86
|
+
const stopPersisting = state.persist('state.user')
|
|
78
87
|
|
|
79
88
|
observer('state.user', user => {
|
|
80
89
|
console.log(user)
|
|
81
90
|
})
|
|
82
91
|
```
|
|
83
92
|
|
|
93
|
+
`state.persist()` creates a bidirectional mirror between `state` (live in-memory)
|
|
94
|
+
and `store` (durable copy). It seeds the initial value from `store` if present,
|
|
95
|
+
then every write to that path flows to `store` automatically. The return value is
|
|
96
|
+
an unsubscribe function - call it to stop the mirroring (the value already in
|
|
97
|
+
`store` is preserved):
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
stopPersisting() // from here, state.user is in-memory only; store no longer updated
|
|
101
|
+
```
|
|
102
|
+
|
|
84
103
|
And this is what makes memorio a *memory* layer, not just a state manager - structured, inspectable facts about a user or agent, not just ephemeral UI state:
|
|
85
104
|
|
|
86
105
|
```ts
|
|
@@ -148,7 +167,6 @@ For most apps, that's enough. Everything below is an optional capability you can
|
|
|
148
167
|
### Other
|
|
149
168
|
| Topic | Reference |
|
|
150
169
|
| --- | --- |
|
|
151
|
-
| Version history | [`CHANGELOG.md`](./CHANGELOG.md) |
|
|
152
170
|
| 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
171
|
| Architecture decisions | [`adr/`](./adr/) |
|
|
154
172
|
|
|
@@ -159,9 +177,9 @@ For most apps, that's enough. Everything below is an optional capability you can
|
|
|
159
177
|
Memorio is upfront about what it doesn't do, so you don't find out the hard way:
|
|
160
178
|
|
|
161
179
|
- **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
|
-
- **Namespaces/contexts aren't a security boundary.** `memorio.isolate()` gives you logical separation between tenants or sessions, not authorization or access control
|
|
163
|
-
- **SQLite persistence
|
|
164
|
-
- **`memory.context()` is rule-based, not embedding-based.** It ranks structured entries by recency, confidence, and type
|
|
180
|
+
- **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.
|
|
181
|
+
- **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).
|
|
182
|
+
- **`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
183
|
- **Key management is your responsibility.** Memorio's encryption is client-side; it doesn't manage, rotate, or store keys for you.
|
|
166
184
|
|
|
167
185
|
---
|
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` |
|
|
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). |
|
|
@@ -1,57 +1,60 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sqlite-batched-writes.ts
|
|
3
|
-
*
|
|
4
|
-
* Scenario: importing or writing many rows into memorio's sqlite layer.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* incremental.
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
await memorio.sqlite.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// await memorio.sqlite.
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
1
|
+
/**
|
|
2
|
+
* sqlite-batched-writes.ts
|
|
3
|
+
*
|
|
4
|
+
* Scenario: importing or writing many rows into memorio's sqlite layer.
|
|
5
|
+
*
|
|
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.
|
|
10
|
+
*/
|
|
11
|
+
import { memorio } from 'memorio'
|
|
12
|
+
|
|
13
|
+
interface UserRow {
|
|
14
|
+
id: number
|
|
15
|
+
name: string
|
|
16
|
+
role: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function importUsers(users: UserRow[]) {
|
|
20
|
+
await memorio.sqlite.ready
|
|
21
|
+
await memorio.sqlite.db.create('app', { persistence: true })
|
|
22
|
+
|
|
23
|
+
await memorio.sqlite.query.run(
|
|
24
|
+
'app',
|
|
25
|
+
`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, role TEXT)`
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
// Bad: this would trigger a full checkpoint after every single insert.
|
|
29
|
+
//
|
|
30
|
+
// for (const user of users) {
|
|
31
|
+
// await memorio.sqlite.query.run('app', 'INSERT INTO users ...', [...])
|
|
32
|
+
// await memorio.sqlite.db.flush('app') // <- don't do this per row
|
|
33
|
+
// }
|
|
34
|
+
|
|
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.
|
|
38
|
+
for (const user of users) {
|
|
39
|
+
await memorio.sqlite.query.run(
|
|
40
|
+
'app',
|
|
41
|
+
`INSERT INTO users (id, name, role) VALUES (?, ?, ?)`,
|
|
42
|
+
[user.id, user.name, user.role]
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Flush explicitly, once, after the whole batch - check the installed
|
|
47
|
+
// version's API for the exact flush/persist call name if it differs from
|
|
48
|
+
// automatic persistence-on-close.
|
|
49
|
+
const admins = await memorio.sqlite.query.select(
|
|
50
|
+
'app',
|
|
51
|
+
`SELECT * FROM users WHERE role = ?`,
|
|
52
|
+
['admin']
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return admins
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// For read-heavy or scratch-space use where durability doesn't matter,
|
|
59
|
+
// skip { persistence: true } entirely - sqlite runs in memory by default,
|
|
60
|
+
// which avoids journal and checkpoint overhead altogether.
|