memorio 4.9.35 → 5.0.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.
Files changed (76) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +307 -359
  3. package/SECURITY.md +17 -1
  4. package/SUMMARY.md +59 -45
  5. package/adr/001-state-proxy-model.md +96 -0
  6. package/adr/002-observer-semantics.md +180 -0
  7. package/adr/003-deep-mutation-semantics.md +129 -0
  8. package/adr/004-array-mutation-semantics.md +128 -0
  9. package/adr/005-scheduler-contract.md +149 -0
  10. package/adr/006-context-isolation.md +92 -0
  11. package/adr/007-mutation-records.md +118 -0
  12. package/adr/008-transactions.md +106 -0
  13. package/adr/009-history-model.md +110 -0
  14. package/adr/README.md +46 -0
  15. package/adr/template.md +49 -0
  16. package/examples/basic.ts +115 -115
  17. package/examples/browser-vanilla.html +358 -358
  18. package/examples/cache.ts +72 -72
  19. package/examples/cross-platform-guards.ts +57 -57
  20. package/examples/history.ts +104 -0
  21. package/examples/idb.ts +109 -109
  22. package/examples/multi-tenant-context.ts +44 -44
  23. package/examples/node-server.ts +308 -308
  24. package/examples/observer.ts +60 -60
  25. package/examples/platform.ts +115 -115
  26. package/examples/react-app.tsx +362 -362
  27. package/examples/react-observer.tsx +63 -63
  28. package/examples/semantic-memory.ts +60 -60
  29. package/examples/session-advanced.ts +91 -91
  30. package/examples/sqlite-batched-writes.ts +57 -57
  31. package/examples/state-advanced.ts +89 -89
  32. package/examples/store-advanced.ts +117 -117
  33. package/examples/sync.ts +90 -0
  34. package/examples/typed-and-schema.ts +102 -100
  35. package/examples/useObserver.tsx +140 -141
  36. package/global.cjs +4594 -0
  37. package/global.d.ts +8 -0
  38. package/global.js +4532 -0
  39. package/index.cjs +700 -678
  40. package/index.d.ts +1 -0
  41. package/index.js +680 -677
  42. package/llms.txt +72 -4
  43. package/markdown/AUDIT-REPORT.md +135 -0
  44. package/markdown/CACHE.md +100 -0
  45. package/markdown/CHANGELOG.md +243 -0
  46. package/markdown/DEVTOOLS.md +129 -0
  47. package/markdown/DISPATCH.md +177 -0
  48. package/markdown/HISTORY.md +199 -0
  49. package/markdown/IDB.md +178 -0
  50. package/markdown/IMPORT.md +153 -0
  51. package/markdown/INSPECT.md +123 -0
  52. package/markdown/LOGGER.md +154 -0
  53. package/markdown/MEMORY-ATTACHMENT.md +96 -0
  54. package/markdown/MEMORY.md +162 -0
  55. package/markdown/OBSERVER.md +209 -0
  56. package/markdown/PLATFORM.md +271 -0
  57. package/markdown/PROJECT.md +311 -0
  58. package/markdown/SCHEMA.md +176 -0
  59. package/markdown/SECURITY.md +330 -0
  60. package/markdown/SESSION.md +165 -0
  61. package/markdown/SQLITE.md +190 -0
  62. package/markdown/STATE.md +160 -0
  63. package/markdown/STORE.md +171 -0
  64. package/markdown/SYNC.md +319 -0
  65. package/markdown/TYPED.md +165 -0
  66. package/markdown/USEOBSERVER.md +257 -0
  67. package/modules/redux.cjs +320 -167
  68. package/modules/redux.cjs.map +1 -1
  69. package/modules/redux.js +320 -167
  70. package/modules/redux.js.map +1 -1
  71. package/package.json +13 -3
  72. package/types/env.d.ts +19 -9
  73. package/types/exports.d.ts +20 -0
  74. package/types/history.d.ts +13 -1
  75. package/types/memorio.d.ts +17 -5
  76. package/types/mutation.d.ts +75 -0
@@ -0,0 +1,330 @@
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Deciders:** Memorio 5.x Core Team
4
+ > **Scope**: Security Documentation
5
+ > **Standard**: NIST SP 800-53, OWASP ASVS, NSA Cybersecurity Guidelines
6
+ >
7
+ ---
8
+ # Memorio Security Documentation
9
+
10
+ > Last Updated: v3.0.2
11
+
12
+ This document describes the security measures implemented in Memorio to protect against common vulnerabilities and ensure safe operation across different platforms.
13
+
14
+ ---
15
+
16
+ ## Security Overview
17
+
18
+ Memorio implements multiple layers of security to protect user data and prevent common attack vectors:
19
+
20
+ | Security Feature | Status | Description |
21
+ |------------------|--------|-------------|
22
+ | Cryptographically Secure IDs | ✅ Enabled | Session/Context IDs use crypto.randomUUID |
23
+ | Input Validation | ✅ Enabled | Key length limits + character filtering |
24
+ | Session Isolation | ✅ Enabled | Unique namespaces per session |
25
+ | Context Isolation | ✅ Enabled | Separate storage per tenant |
26
+ | No Code Injection | ✅ Enabled | No eval() or dynamic code execution |
27
+ | XSS Prevention | ✅ Enabled | No innerHTML or document.write |
28
+
29
+ ---
30
+
31
+ ## 1. Cryptographically Secure Random Generation
32
+
33
+ ### Implementation
34
+
35
+ Session and context IDs are generated using cryptographically secure random values:
36
+
37
+ ```typescript
38
+ // config/platform.ts
39
+ function generateSessionId(): string {
40
+ // Priority 1: crypto.randomUUID (most secure)
41
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
42
+ return crypto.randomUUID()
43
+ }
44
+
45
+ // Priority 2: crypto.getRandomValues (secure fallback)
46
+ if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
47
+ const array = new Uint8Array(16)
48
+ crypto.getRandomValues(array)
49
+ return Array.from(array, b => b.toString(16).padStart(2, '0')).join('')
50
+ }
51
+
52
+ // Priority 3: Math.random (last resort - less secure)
53
+ return `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`
54
+ }
55
+ ```
56
+
57
+ ### Random Source Priority
58
+
59
+ | Priority | Method | Security Level |
60
+ |----------|--------|----------------|
61
+ | 1 | `crypto.randomUUID()` | 🔒 FIPS 140-2 compliant |
62
+ | 2 | `crypto.getRandomValues()` | 🔒 Cryptographically secure |
63
+ | 3 | `Math.random()` | ⚠️ Not for security purposes |
64
+
65
+ ---
66
+
67
+ ## 2. Input Validation & Key Sanitization
68
+
69
+ All storage keys are validated before use to prevent injection attacks:
70
+
71
+ ### Validation Rules
72
+
73
+ | Rule | Limit | Action on Violation |
74
+ |------|-------|---------------------|
75
+ | Key Length | Max 512 chars | Reject with debug message |
76
+ | Character Set | `[a-zA-Z0-9_.-]` | Reject with debug message |
77
+ | Type Check | Must be string | Return empty/null |
78
+
79
+ ### Implementation
80
+
81
+ ```typescript
82
+ function _prefixKey(name: string): string {
83
+ // Validate key
84
+ if (!name || typeof name !== 'string') return ''
85
+ if (name.length > 512) {
86
+ console.debug('Key too long (max 512 characters)')
87
+ return ''
88
+ }
89
+ // Sanitize: only allow alphanumeric, underscore, dash, dot
90
+ if (!/^[a-zA-Z0-9_.-]+$/.test(name)) {
91
+ console.debug('Key contains invalid characters')
92
+ return ''
93
+ }
94
+ return _sessionPrefix + name
95
+ }
96
+ ```
97
+
98
+ ### Allowed Characters Table
99
+
100
+ | Character Type | Allowed | Example |
101
+ |----------------|---------|---------|
102
+ | Lowercase | ✅ | `username`, `user_data` |
103
+ | Uppercase | ✅ | `USER`, `UserName` |
104
+ | Numbers | ✅ | `user123`, `data_2024` |
105
+ | Underscore | ✅ | `user_name`, `_private` |
106
+ | Dash | ✅ | `user-id`, `data-set` |
107
+ | Dot | ✅ | `user.profile`, `data.json` |
108
+ | Special Chars | ❌ | `<script>`, `../../../etc` |
109
+
110
+ ---
111
+
112
+ ## 3. Session Isolation
113
+
114
+ Each session gets a unique namespace to prevent data leakage:
115
+
116
+ ### Isolation Mechanism
117
+
118
+ | Component | Without Context | With Context |
119
+ |-----------|-----------------|--------------|
120
+ | Session ID | `crypto.randomUUID()` | Context name |
121
+ | Store Keys | `memorio_store_[uuid]-keyname` | `[contextName]-keyname` |
122
+ | Session Keys | `memorio_session_[uuid]-keyname` | `[contextName]-keyname` |
123
+ | State | In-memory (per-instance) | In-memory (per-instance) |
124
+
125
+ ### Key Prefix Format
126
+
127
+ ```
128
+ // Without context:
129
+ memorio_store-[session-uuid]-username
130
+ memorio_session-[session-uuid]-auth-token
131
+
132
+ // With context (createContext('user-123')):
133
+ user-123-username
134
+ user-123-auth-token
135
+ ```
136
+
137
+ ### Cross-Session Protection
138
+
139
+ | Scenario | Protection |
140
+ |----------|------------|
141
+ | Browser Tabs | Each tab has unique session ID |
142
+ | Server Requests | Each request can use separate context |
143
+ | Multi-Tenant | `memorio.createContext()` isolates tenants |
144
+
145
+ ---
146
+
147
+ ## 4. Context Isolation (Multi-Tenant)
148
+
149
+ For server-side applications, contexts provide complete data isolation:
150
+
151
+ ```typescript
152
+ // Create isolated context per tenant
153
+ const tenantA = memorio.isolate('tenant-A')
154
+ const tenantB = memorio.isolate('tenant-B')
155
+
156
+ // Each context has completely separate storage
157
+ tenantA.state.secret = 'Tenant A data' // Isolated
158
+ tenantB.state.secret = 'Tenant B data' // Isolated
159
+ ```
160
+
161
+ ### Context Security
162
+
163
+ | Feature | Description |
164
+ |---------|-------------|
165
+ | Unique ID | Each context gets unique identifier |
166
+ | Separate Storage | State, Store, Session, Cache all isolated |
167
+ | No Cross-Context Access | Impossible to read other contexts |
168
+ | Cleanup | `deleteContext()` removes all data |
169
+
170
+ ---
171
+
172
+ ## 5. Data Serialization Security
173
+
174
+ ### Safe Operations
175
+
176
+ | Operation | Security Measure |
177
+ |-----------|-----------------|
178
+ | `store.set()` | JSON.stringify only allowed types |
179
+ | `store.get()` | JSON.parse with try-catch |
180
+ | Functions | Blocked with debug message |
181
+ | Objects | Deep-cloned on read |
182
+
183
+ ### Blocked Types
184
+
185
+ ```typescript
186
+ // These are blocked and logged:
187
+ store.set('myFunc', () => {}) // "It's not secure to store functions."
188
+ store.set('mySymbol', Symbol('test')) // Would fail serialization
189
+ ```
190
+
191
+ ---
192
+
193
+ ## 6. Platform-Specific Security
194
+
195
+ ### Browser Environment
196
+
197
+ | Feature | Security |
198
+ |---------|----------|
199
+ | localStorage | Same-origin policy applies |
200
+ | sessionStorage | Tab isolation |
201
+ | IndexedDB | Same-origin policy |
202
+ | HTTPS Required | Recommended for production |
203
+
204
+ ### Server Environment (Node.js/Deno)
205
+
206
+ | Feature | Security |
207
+ |---------|----------|
208
+ | In-Memory Storage | Process-scoped only |
209
+ | Context Isolation | Per-request isolation recommended |
210
+ | No Persistence | Data lost on restart (by design) |
211
+
212
+ ---
213
+
214
+ ## 7. Security Best Practices
215
+
216
+ ### For Developers
217
+
218
+ 1. **Use Contexts in Server Apps**
219
+ ```typescript
220
+ // Express middleware
221
+ app.use((req, res, next) => {
222
+ req.memorio = memorio.createContext(`req-${req.id}`)
223
+ next()
224
+ })
225
+ ```
226
+
227
+ 2. **Validate Keys**
228
+ ```typescript
229
+ // Don't use user input directly as keys
230
+ const safeKey = sanitize(userInput) // Input validation
231
+ store.set(safeKey, value)
232
+ ```
233
+
234
+ 3. **Check Persistence**
235
+ ```typescript
236
+ if (!store.isPersistent) {
237
+ console.warn('Data not persisted!')
238
+ }
239
+ ```
240
+
241
+ 4. **Clear Sensitive Data**
242
+ ```typescript
243
+ // On logout
244
+ session.removeAll()
245
+ state.removeAll()
246
+ ```
247
+
248
+ ### For Security Audits
249
+
250
+ | Check | Location |
251
+ |-------|----------|
252
+ | Random Generation | `config/platform.ts:44` |
253
+ | Key Validation | `functions/store/index.ts:31` |
254
+ | Session Isolation | `functions/session/index.ts:27` |
255
+ | Context System | `config/platform.ts:301` |
256
+
257
+ ---
258
+
259
+ ## 8. Vulnerability Prevention
260
+
261
+ ### Prevention Matrix
262
+
263
+ | Vulnerability | Prevention | Status |
264
+ |---------------|------------|--------|
265
+ | XSS | No innerHTML/document.write | ✅ |
266
+ | Code Injection | No eval/Function | ✅ |
267
+ | Key Injection | Character whitelist | ✅ |
268
+ | DoS | 512 char key limit | ✅ |
269
+ | Session Hijacking | Unique session IDs | ✅ |
270
+ | Data Leakage | Namespace isolation | ✅ |
271
+ | CSRF | Browser Same-Origin | ✅ |
272
+
273
+ ---
274
+
275
+ ## 9. Compliance
276
+
277
+ ### Standards Alignment
278
+
279
+ | Standard | Compliance |
280
+ |----------|------------|
281
+ | NIST SP 800-53 | ✅ Cryptographic standards |
282
+ | OWASP Top 10 | ✅ Key injection prevention |
283
+ | CWE | ✅ Common weaknesses addressed |
284
+ | FIPS 140-2 | ✅ crypto.randomUUID |
285
+
286
+ ---
287
+
288
+ ## 10. Reporting Security Issues
289
+
290
+ If you discover a security vulnerability in Memorio:
291
+
292
+ 1. **Do NOT** open a public GitHub issue
293
+ 2. **Email**: security@example.com (replace with actual contact)
294
+ 3. **Include**: Vulnerability details, steps to reproduce, potential impact
295
+
296
+ ### Response Timeline
297
+
298
+ | Phase | Timeline |
299
+ |-------|----------|
300
+ | Acknowledgment | 48 hours |
301
+ | Initial Assessment | 7 days |
302
+ | Fix Released | Based on severity |
303
+
304
+ ---
305
+
306
+ ## Security Changelog
307
+
308
+ ### v3.0.2 (Current)
309
+
310
+ - ✅ Removed esbuild-sass-plugin / esbuild-scss-modules-plugin (SCSS attack vector eliminated)
311
+ - ✅ `store.set()` now blocks function values instead of silently continuing
312
+ - ✅ All `PRIVATE License` headers in `functions/idb/` replaced with `MIT`
313
+ - ✅ `buildPathTracker` dead code removed from state
314
+ - ✅ `Object.freeze(observer)` call removed (undeclared variable, caused `ReferenceError`)
315
+ - ✅ `confirm()` removed from `idb.db.delete()` (no blocking UI calls in libraries)
316
+ - ✅ Fully generated changelog for v3.0.2 across all github docs
317
+
318
+ ---
319
+
320
+ ### v2.7.0 - Previous
321
+
322
+ - ✅ Added `crypto.getRandomValues()` fallback
323
+ - ✅ Added key length validation (512 chars)
324
+ - ✅ Added character whitelist validation
325
+ - ✅ Improved session isolation
326
+ - ✅ Context isolation for multi-tenancy
327
+
328
+ ---
329
+
330
+ *This document was last updated for Memorio v3.0.2*
@@ -0,0 +1,165 @@
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Deciders:** Memorio 5.x Core Team
4
+ > **Scope**: API Reference
5
+ > **Standard**: Memorio API Specification v5
6
+ >
7
+ ---
8
+ # Session - Memorio
9
+
10
+ > 🖥️ **Browser & Edge**: Uses sessionStorage for persistence
11
+ > ⚙️ **Node.js/Deno**: Falls back to in-memory storage (not persistent)
12
+
13
+ Session provides temporary storage using browser sessionStorage. Data persists until the tab or window is closed.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install memorio
19
+ ```
20
+
21
+ ```javascript
22
+ import { session } from 'memorio';
23
+ ```
24
+
25
+ > **Classic `import`**: `session` is also available via the global entrypoint.
26
+ > `import 'memorio/global'` exposes the same instance as `globalThis.session`.
27
+
28
+ ---
29
+
30
+ ## Quick Examples
31
+
32
+ ### Example 1: Basic Usage
33
+
34
+ ```javascript
35
+ // Save session data
36
+ session.set('token', 'abc123');
37
+ session.set('userId', 42);
38
+
39
+ // Read session data
40
+ console.debug(session.get('token')); // "abc123"
41
+
42
+ // Check persistence
43
+ console.debug(session.isPersistent); // true in browser, false in Node.js/Deno
44
+ ```
45
+
46
+ ### Example 2: Intermediate
47
+
48
+ ```javascript
49
+ // Store objects
50
+ session.set('user', { name: 'Mario', role: 'admin' });
51
+
52
+ // Remove specific item
53
+ session.remove('token');
54
+
55
+ // Clear all session data
56
+ session.removeAll();
57
+ ```
58
+
59
+ ### Example 3: Advanced
60
+
61
+ ```javascript
62
+ // Check if session has data
63
+ if (session.get('authToken')) {
64
+ // User is logged in
65
+ }
66
+
67
+ // Get storage quota (returns Promise<[usage, quota]> in KB)
68
+ const [used, total] = await session.quota();
69
+ console.debug(`Using ${used} out of ${total} KB`);
70
+
71
+ // Get total size in characters
72
+ const size = session.size();
73
+ console.debug(`${size} bytes`);
74
+
75
+ // Handle session expiry
76
+ window.addEventListener('storage', (e) => {
77
+ if (e.key === 'session' && !e.newValue) {
78
+ // Session cleared
79
+ redirectToLogin();
80
+ }
81
+ });
82
+ ```
83
+
84
+ ---
85
+
86
+ ## API Reference
87
+
88
+ ### Methods
89
+
90
+ | Method | Parameters | Returns | Description |
91
+ |--------|------------|---------|-------------|
92
+ | `session.get(name)` | `name: string` | `any` | Get value from session |
93
+ | `session.set(name, value)` | `name: string, value: any` | `void` | Save value to session |
94
+ | `session.remove(name)` | `name: string` | `boolean` | Remove single item |
95
+ | `session.delete(name)` | `name: string` | `boolean` | Alias for remove |
96
+ | `session.removeAll()` | `none` | `boolean` | Clear all session data |
97
+ | `session.clearAll()` | `none` | `boolean` | Alias for removeAll |
98
+ | `session.size()` | `none` | `number` | Get total size in characters |
99
+ | `session.quota()` | `none` | `Promise<[number, number]>` | Get storage usage/quota in KB |
100
+
101
+ ### Properties
102
+
103
+ | Property | Type | Description |
104
+ |----------|------|-------------|
105
+ | `session.isPersistent` | `boolean` | `true` if using real sessionStorage, `false` if in-memory fallback |
106
+
107
+ ---
108
+
109
+ ## Store vs Session
110
+
111
+ | Feature | Store | Session |
112
+ |---------|-------|---------|
113
+ | Storage | localStorage | sessionStorage |
114
+ | Lifetime | Forever | Until tab closes |
115
+ | Use case | User preferences | Temporary auth |
116
+ | Shared across tabs | Yes | No |
117
+ | Platform | Browser/Edge | Browser/Edge |
118
+ | Persistence | ✅ Always | ✅ Browser only |
119
+
120
+ ---
121
+
122
+ ## Platform Notes
123
+
124
+ | Platform | Behavior |
125
+ |----------|----------|
126
+ | Browser | Uses real sessionStorage - data persists until tab closes |
127
+ | Edge Worker | Uses real sessionStorage |
128
+ | Node.js | In-memory fallback - data lost on process restart |
129
+ | Deno | In-memory fallback - data lost on process restart |
130
+
131
+ ---
132
+
133
+ ## Best Practices
134
+
135
+ 1. Use for auth tokens: `session.set('token', jwt)`
136
+ 2. Clear on logout: `session.removeAll()`
137
+ 3. Don't use for persistent data
138
+ 4. Check for null: `session.get('key') || defaultValue`
139
+
140
+ ---
141
+
142
+ ## Common Use Cases
143
+
144
+ ### Authentication
145
+
146
+ ```javascript
147
+ // Login
148
+ session.set('authToken', response.token);
149
+ session.set('user', response.user);
150
+
151
+ // Logout
152
+ session.removeAll();
153
+ router.push('/login');
154
+ ```
155
+
156
+ ### Form Progress
157
+
158
+ ```javascript
159
+ // Save form draft
160
+ session.set('formDraft', formData);
161
+
162
+ // Restore on page refresh
163
+ const draft = session.get('formDraft');
164
+ if (draft) restoreForm(draft);
165
+ ```
@@ -0,0 +1,190 @@
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Deciders:** Memorio 5.x Core Team
4
+ > **Scope**: API Reference
5
+ > **Standard**: Memorio API Specification v5
6
+ >
7
+ ---
8
+ # SQLite - Memorio
9
+
10
+ > 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.
11
+
12
+ SQLite brings a full SQL engine into the browser through [`sql.js`](https://sql.js.org), a port of SQLite to JavaScript via WebAssembly. Memorio loads it **lazily** on first use, so it only affects bundles that actually use the `sqlite` module.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install memorio
18
+ # Optional: install the SQLite engine locally (the default loader fetches it from the CDN)
19
+ npm install sql.js
20
+ ```
21
+
22
+ ```javascript
23
+ import { sqlite } from 'memorio';
24
+ ```
25
+
26
+ > **Global API**: `import 'memorio/global'` is the opt-in entrypoint that also exposes `state`, `store`, `session`, `cache`, `idb`, `sqlite`, `observer`, and `useObserver` on `globalThis`.
27
+
28
+ > The default loader injects the sql.js UMD build (`sql-wasm-browser.js`) from the jsDelivr CDN as a classic `<script>`, exposing the `initSqlJs` factory on `globalThis`. This keeps `sql.js` (and its WASM) out of your build graph entirely - it's only fetched when `sqlite` is first used. For production/self-hosted setups, install `sql.js` and configure a custom `loader` (e.g. `sqlite.config({ loader: () => import('sql.js') })` under a bundler), or set the wasm base with `sqlite.config({ wasmUrl })` / `sqlite.config({ locateFile })`.
29
+
30
+ ---
31
+
32
+ ## Quick Examples
33
+
34
+ ### Example 1: Basic Usage
35
+
36
+ ```javascript
37
+ // Create an in-memory database and a table
38
+ await sqlite.db.create('myApp');
39
+ await sqlite.query.run('myApp', 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)');
40
+
41
+ // Insert data
42
+ await sqlite.query.run('myApp', 'INSERT INTO users (name) VALUES (?)', ['Mario']);
43
+
44
+ // Select data
45
+ const rows = await sqlite.query.select('myApp', 'SELECT * FROM users');
46
+ console.debug(rows); // [{ id: 1, name: 'Mario' }]
47
+ ```
48
+
49
+ ### Example 2: CRUD shortcuts
50
+
51
+ ```javascript
52
+ const db = 'store';
53
+
54
+ await sqlite.db.create(db);
55
+ await sqlite.query.run(db, 'CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price REAL)');
56
+ await sqlite.data.set(db, 'INSERT INTO products (name, price) VALUES (?, ?)', ['Apple', 1.5]);
57
+ await sqlite.data.set(db, 'INSERT INTO products (name, price) VALUES (?, ?)', ['Banana', 0.8]);
58
+
59
+ // First matching row
60
+ const apple = await sqlite.data.get(db, 'SELECT * FROM products WHERE name = ?', ['Apple']);
61
+ console.debug(apple); // { id: 1, name: 'Apple', price: 1.5 }
62
+ ```
63
+
64
+ ### Example 3: Export / Import
65
+
66
+ ```javascript
67
+ await sqlite.db.create('myApp');
68
+ await sqlite.query.run('myApp', 'CREATE TABLE todos (id INTEGER PRIMARY KEY, task TEXT)');
69
+ await sqlite.data.set('myApp', 'INSERT INTO todos (task) VALUES (?)', ['Write docs']);
70
+
71
+ // Export the in-memory database to a portable binary dump
72
+ const dump = await sqlite.db.export('myApp');
73
+
74
+ // Later... import it back
75
+ await sqlite.db.import('restored', dump);
76
+ const rows = await sqlite.query.select('restored', 'SELECT * FROM todos');
77
+ ```
78
+
79
+ ### Example 4: Engine control
80
+
81
+ ```javascript
82
+ // Configure the wasm location BEFORE first use (sets the locateFile base)
83
+ sqlite.config({ wasmUrl: '/static/sql.js/' });
84
+
85
+ // Or provide a fully custom loader (e.g. a local/npm build of sql.js)
86
+ sqlite.config({ loader: async () => {
87
+ return await import('sql.js'); // local install - resolves at runtime
88
+ }});
89
+
90
+ // Enable automatic persistence of one or more databases (see Example 5)
91
+ sqlite.config({ persistence: true });
92
+
93
+ // Wait until the engine is ready
94
+ await sqlite.ready;
95
+ console.debug('SQLite version:', sqlite.db.version());
96
+ ```
97
+
98
+ ### Example 5: Persistence & dev download
99
+
100
+ > **Important:** sql.js databases live in **WebAssembly memory** - they are
101
+ > in-memory and **volatile** (lost on page refresh) unless you persist them.
102
+
103
+ ```javascript
104
+ // Opt into auto-persistence at create time (global config or per-create)
105
+ await sqlite.db.create('app', { persistence: true });
106
+
107
+ await sqlite.query.run('app', 'CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT)');
108
+ // writes are snapshotted to localStorage automatically (debounced via updateHook)
109
+
110
+ await sqlite.db.persist('app'); // force an immediate snapshot
111
+ // After a refresh, reopening restores the data:
112
+ await sqlite.db.create('app', { persistence: true });
113
+
114
+ // Dev convenience: download the current db as a .sqlite file from the browser
115
+ await sqlite.db.download('app', 'app.sqlite');
116
+
117
+ // Flush + persist + release the handle
118
+ await sqlite.db.close('app');
119
+ ```
120
+
121
+ Persistence is stored on `store` (localStorage, namespaced per
122
+ `sqlite.config({ namespace })` / memorio context) as a base64 snapshot under
123
+ `memorio:sqlite:db:<ns>:<name>`. It is best-effort: if `store` is unavailable
124
+ the database simply behaves as in-memory.
125
+
126
+ ---
127
+
128
+ ## API Reference
129
+
130
+ ### Engine Control
131
+
132
+ | Method | Parameters | Returns | Description |
133
+ |--------|------------|---------|-------------|
134
+ | `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. |
135
+ | `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. |
136
+ | `sqlite.db.persist(name)` | `name: string` | `Promise<boolean>` | Force an immediate snapshot of a persisted database to `store`. |
137
+ | `sqlite.db.download(name, filename?)` | `name: string, filename?: string` | `Promise<boolean>` | Dev-only: trigger a browser download of the db as a `.sqlite` file. |
138
+ | `sqlite.db.close(name)` | `name: string` | `Promise<void>` | Persist (if enabled), close, and release the handle. |
139
+ | `sqlite.ready` | none | `Promise<void>` | Resolves once `sql.js` has been initialized. Rejects (and sets `_disabled`) if the engine can't load. |
140
+ | `sqlite.db.version()` | none | `string \| null` | Engine version, available after initialization. |
141
+ | `sqlite._disabled` | none | `boolean` | `true` when the module is disabled (non-browser env / load failure). |
142
+ | `sqlite._warning` | none | `string \| undefined` | Reason text when disabled, if applicable. |
143
+
144
+ ### Database Methods
145
+
146
+ | Method | Parameters | Returns | Description |
147
+ |--------|------------|---------|-------------|
148
+ | `sqlite.db.support()` | none | `boolean` | Check whether SQLite can run in this environment. |
149
+ | `sqlite.db.create(name, opts?)` | `name: string`, `opts?: { data }` | `Promise<Database>` | Create an in-memory database (or reopen one from a binary dump). |
150
+ | `sqlite.db.get(name)` | `name: string` | `Database` | Retrieve an open database handle. |
151
+ | `sqlite.db.delete(name)` | `name: string` | `boolean` | Close and remove a database handle. |
152
+ | `sqlite.db.list()` | none | `string[]` | List open database names. |
153
+ | `sqlite.db.size(name?)` | `name?: string` | `Promise<number>` | Size in bytes of one or all databases. |
154
+ | `sqlite.db.export(name)` | `name: string` | `Promise<Uint8Array>` | Export a database to a binary dump. |
155
+ | `sqlite.db.import(name, data)` | `name: string`, `data` | `Promise<Database>` | Create/replace a database from a binary dump. |
156
+
157
+ ### Query Methods
158
+
159
+ | Method | Parameters | Returns | Description |
160
+ |--------|------------|---------|-------------|
161
+ | `sqlite.query.run(name, sql, params?)` | `name: string`, `sql: string`, `params?: any[]` | `Promise<number>` | Run a statement that does not return rows (INSERT / UPDATE / DELETE / CREATE). Returns modified-row count. |
162
+ | `sqlite.query.select(name, sql, params?)` | `name: string`, `sql: string`, `params?: any[]` | `Promise<object[]>` | Run a query and return the rows as plain objects. |
163
+
164
+ ### Data Methods (CRUD shortcuts)
165
+
166
+ | Method | Parameters | Returns | Description |
167
+ |--------|------------|---------|-------------|
168
+ | `sqlite.data.set(name, sql, params?)` | `name: string`, `sql: string`, `params?: any[]` | `Promise<number>` | Alias of `sqlite.query.run`. |
169
+ | `sqlite.data.get(name, sql, params?)` | `name: string`, `sql: string`, `params?: any[]` | `Promise<object \| null>` | Alias of `sqlite.query.select` returning the first row (or `null`). |
170
+
171
+ ---
172
+
173
+ ## Platform Support
174
+
175
+ | Platform | Support | Notes |
176
+ |----------|---------|-------|
177
+ | Browser | ✅ Full | Requires WebAssembly + the `sql.js` package (or CDN fallback) |
178
+ | Edge Worker | ⚠️ Limited | WebAssembly may be available; configure a `loader` manually |
179
+ | Node.js | ❌ Not available | Use `store` or `session` instead |
180
+ | Deno | ❌ Not available | Use `store` or `session` instead |
181
+
182
+ ---
183
+
184
+ ## Best Practices
185
+
186
+ 1. Configure the wasm path for production: `sqlite.config({ wasmUrl })` or `sqlite.config({ loader })`.
187
+ 2. Create one named database per feature and reuse the handle: `const db = await sqlite.db.create('app')`.
188
+ 3. Always release databases you no longer need: `sqlite.db.delete('temp')`.
189
+ 4. Use `await sqlite.ready` before running statements to ensure the engine is loaded.
190
+ 5. Use `?` placeholders and `params` to avoid SQL injection.